diff --git a/examples/cpp/marble-game/ClickOnThat.cpp b/examples/cpp/marble-game/ClickOnThat.cpp index 488a3bfe4..a508f22cb 100644 --- a/examples/cpp/marble-game/ClickOnThat.cpp +++ b/examples/cpp/marble-game/ClickOnThat.cpp @@ -1,378 +1,374 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Abhinav Gangwar // // Self #include "ClickOnThat.h" // Qt #include #include #include #include #include // Marble #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include - namespace Marble { class ClickOnThatPrivate { public: ClickOnThatPrivate( MarbleWidget *marbleWidget ) : m_marbleWidget( marbleWidget ), m_parent( 0 ), m_correctAnswerPlacemark( 0 ), m_selectPinDocument( 0 ), m_countryNames( 0 ), m_countryBoundaries( 0 ) { m_continentsAndOceans << QStringLiteral("Asia") << QStringLiteral("Africa") << QStringLiteral("North America") << QStringLiteral("South America") << QStringLiteral("Antarctica") << QStringLiteral("Europe") << QStringLiteral("Australia") << QStringLiteral("Arctic Ocean") << QStringLiteral("Indian Ocean") << QStringLiteral("North Atlantic Ocean") << QStringLiteral("North Pacific Ocean") << QStringLiteral("South Pacific Ocean") << QStringLiteral("South Atlantic Ocean") << QStringLiteral("Southern Ocean"); } ~ClickOnThatPrivate() { delete m_selectPinDocument; } MarbleWidget *m_marbleWidget; ClickOnThat *m_parent; /** * Store the GeoDataPlacemark also * for the correct answer so that * we can highlight and zoom in * ( to fit in the current view port ) * to this placemark when user * choses to view the right answer. */ GeoDataPlacemark *m_correctAnswerPlacemark; GeoDataCoordinates m_correctAnswer; /** * @p m_selectPinDocument shows a pin * on map indicating whether the user * has clicked on right country */ GeoDataDocument *m_selectPinDocument; /** * Document to store point placemarks which * have country names ( from file "boundaryplacemarks.cache" ) */ GeoDataDocument *m_countryNames; /** * Document which have placemarks whose geometry * specifies the boundaries of a country * (from file "ne_50m_admin_0_countries.pn2" ) */ GeoDataDocument *m_countryBoundaries; /* * If the placemark used for posting question * represent a continent, the user needs to click exactly on * a particular country whose geometry contains this point * placemark on map ( Ideally it should be any country * within that continent ). Also, oceans are point placemark, so * user needs to click exactly on same point this placemark * represents ( Ideally it should anywhere within the ocean territory ). * So, to avoid such placemark we will use this list. */ QStringList m_continentsAndOceans; }; ClickOnThat::ClickOnThat( MarbleWidget *marbleWidget ) : QObject(), d( new ClickOnThatPrivate(marbleWidget) ) { d->m_parent = this; connect( this, SIGNAL(announceHighlight(qreal,qreal,GeoDataCoordinates::Unit)), d->m_marbleWidget, SIGNAL(highlightedPlacemarksChanged(qreal,qreal,GeoDataCoordinates::Unit)) ); } ClickOnThat::~ClickOnThat() { delete d; } void ClickOnThat::disablePinDocument() { if ( d->m_selectPinDocument ) { d->m_selectPinDocument->setVisible( false ); d->m_marbleWidget->model()->treeModel()->updateFeature( d->m_selectPinDocument ); } } void ClickOnThat::initiateGame() { /** * First remove the GeoDataDocument, which displays * country names, from map. */ if ( !d->m_countryNames ) { const GeoDataTreeModel *const treeModel = d->m_marbleWidget->model()->treeModel(); for ( int i = 0; i < treeModel->rowCount(); ++i ) { QVariant const data = treeModel->data ( treeModel->index ( i, 0 ), MarblePlacemarkModel::ObjectPointerRole ); GeoDataObject *object = qvariant_cast( data ); Q_ASSERT_X( object, "CountryByShape::initiateGame", "failed to get valid data from treeModel for GeoDataObject" ); - if ( object->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - GeoDataDocument *doc = static_cast( object ); + if (auto doc = geodata_cast(object)) { QFileInfo fileInfo( doc->fileName() ); if (fileInfo.fileName() == QLatin1String("boundaryplacemarks.cache")) { d->m_countryNames = doc; break; } } } } if ( !d->m_countryBoundaries ) { const GeoDataTreeModel *const treeModel = d->m_marbleWidget->model()->treeModel(); for ( int i = 0; i < treeModel->rowCount(); ++i ) { QVariant const data = treeModel->data ( treeModel->index ( i, 0 ), MarblePlacemarkModel::ObjectPointerRole ); GeoDataObject *object = qvariant_cast( data ); Q_ASSERT_X( object, "MainWindow::initiateGame", "failed to get valid data from treeModel for GeoDataObject" ); - if ( object->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - GeoDataDocument *const doc = static_cast( object ); + if (auto doc = geodata_cast(object)) { QFileInfo fileInfo( doc->fileName() ); if (fileInfo.fileName() == QLatin1String("ne_50m_admin_0_countries.pn2")) { d->m_countryBoundaries = doc; break; } } } } if ( !d->m_selectPinDocument ) { d->m_selectPinDocument = new GeoDataDocument; GeoDataPlacemark *pinPlacemark = new GeoDataPlacemark; GeoDataStyle::Ptr pinStyle(new GeoDataStyle); pinStyle->setId(QStringLiteral("answer")); GeoDataIconStyle iconStyle; iconStyle.setIconPath(MarbleDirs::path(QStringLiteral("bitmaps/target.png"))); pinStyle->setIconStyle( iconStyle ); GeoDataStyleMap styleMap; styleMap.setId(QStringLiteral("default-map")); styleMap.insert(QStringLiteral("normal"), QLatin1Char('#') + pinStyle->id()); d->m_selectPinDocument->addStyle( pinStyle ); d->m_selectPinDocument->addStyleMap( styleMap ); d->m_selectPinDocument->append( pinPlacemark ); pinPlacemark->setStyleUrl(QLatin1Char('#') + styleMap.id()); d->m_selectPinDocument->setVisible( false ); // Add this document to treeModel d->m_marbleWidget->model()->treeModel()->addDocument( d->m_selectPinDocument ); } d->m_marbleWidget->setHighlightEnabled( true ); d->m_marbleWidget->centerOn( 23.0, 42.0 ); d->m_marbleWidget->setDistance( 7500 ); connect( d->m_marbleWidget, SIGNAL(highlightedPlacemarksChanged(qreal,qreal,GeoDataCoordinates::Unit)), this, SLOT(determineResult(qreal,qreal,GeoDataCoordinates::Unit)) ); if ( d->m_countryBoundaries && d->m_countryNames ) { d->m_countryNames->setVisible( false ); d->m_marbleWidget->model()->treeModel()->updateFeature( d->m_countryNames ); emit gameInitialized(); } } void ClickOnThat::postQuestion( QObject *gameObject ) { /** * Find a random placemark */ Q_ASSERT_X( d->m_countryNames, "ClickOnThat::postQuestion", "CountryByShapePrivate::m_countryNames is NULL" ); QVector countryPlacemarks = d->m_countryNames->placemarkList(); uint randomSeed = uint(QTime::currentTime().msec()); qsrand( randomSeed ); GeoDataPlacemark *placemark = 0; GeoDataPoint *point = 0; bool found = false; while( !found ) { placemark = countryPlacemarks[qrand()%countryPlacemarks.size()]; if ( !d->m_continentsAndOceans.contains(placemark->name(), Qt::CaseSensitive) ) { found = true; point = dynamic_cast( placemark->geometry() ); } } if ( point ) { d->m_correctAnswerPlacemark = placemark; d->m_correctAnswer = point->coordinates(); if ( gameObject ) { QMetaObject::invokeMethod( gameObject, "clickOnThatQuestion", Q_ARG(QVariant, QVariant(placemark->name())) ); } } } void ClickOnThat::updateSelectPin(bool result, const GeoDataCoordinates &clickedPoint ) { QDir dir; QString iconPath = dir.absolutePath(); if ( result ) { //iconPath = MarbleDirs::path("bitmaps/MapTackRoundHeadGreen.png"); iconPath += QLatin1String("/MapTackRoundHeadGreen.png"); } else { iconPath += QLatin1String("/MapTackRoundHeadRed.png"); } GeoDataStyle::Ptr style = d->m_selectPinDocument->style(QStringLiteral("answer")); style->iconStyle().setIconPath( iconPath ); d->m_selectPinDocument->addStyle( style ); QVector placemarkList = d->m_selectPinDocument->placemarkList(); if ( placemarkList.size() > 0 ) { placemarkList[0]->setCoordinate( clickedPoint ); } if ( !d->m_selectPinDocument->isVisible() ) { d->m_selectPinDocument->setVisible( true ); } d->m_marbleWidget->model()->treeModel()->updateFeature( d->m_selectPinDocument ); } void ClickOnThat::determineResult( qreal lon, qreal lat, GeoDataCoordinates::Unit unit ) { GeoDataCoordinates coord( lon, lat, 0, unit ); Q_ASSERT_X( d->m_countryNames, "ClickOnThat::determineResult", "CountryByShapePrivate::m_countryBoundaries is NULL" ); QVector::Iterator i = d->m_countryBoundaries->begin(); QVector::Iterator const end = d->m_countryBoundaries->end(); bool foundStandardPoint = false; bool foundClickedPoint = false; for ( ; i != end; ++i ) { GeoDataPlacemark *country = static_cast( *i ); GeoDataPolygon *polygon = dynamic_cast( country->geometry() ); GeoDataLinearRing *linearring = dynamic_cast( country->geometry() ); GeoDataMultiGeometry *multigeom = dynamic_cast( country->geometry() ); foundClickedPoint = false; foundStandardPoint = false; if ( polygon && polygon->contains( coord ) && polygon->contains(d->m_correctAnswer) ) { foundClickedPoint = true; foundStandardPoint = true; d->m_correctAnswerPlacemark = country; break; } if ( linearring && linearring->contains( coord ) && linearring->contains(d->m_correctAnswer) ) { foundClickedPoint = true; foundStandardPoint = true; d->m_correctAnswerPlacemark = country; break; } if ( multigeom ) { QVector::Iterator iter = multigeom->begin(); QVector::Iterator const end = multigeom->end(); for ( ; iter != end; ++iter ) { GeoDataPolygon *poly = dynamic_cast( *iter ); if ( poly && poly->contains( coord ) ) { foundClickedPoint = true; } if ( poly && poly->contains( d->m_correctAnswer ) ) { foundStandardPoint = true; d->m_correctAnswerPlacemark = country; } if ( foundClickedPoint && foundStandardPoint ) { break; } } } if ( foundClickedPoint && foundStandardPoint ) { break; } } if ( foundClickedPoint && foundStandardPoint ) { updateSelectPin( true, coord ); emit updateResult( true ); } else { updateSelectPin( false, coord ); emit updateResult( false ); } } void ClickOnThat::highlightCorrectAnswer() { disconnect( d->m_marbleWidget, SIGNAL(highlightedPlacemarksChanged(qreal,qreal,GeoDataCoordinates::Unit)), this, SLOT(determineResult(qreal,qreal,GeoDataCoordinates::Unit)) ); emit announceHighlight( d->m_correctAnswer.longitude(GeoDataCoordinates::Degree), d->m_correctAnswer.latitude(GeoDataCoordinates::Degree), GeoDataCoordinates::Degree ); updateSelectPin( true, d->m_correctAnswer ); /** * Zoom to highlighted placemark * so that it fits the current * view port */ d->m_marbleWidget->centerOn( *(d->m_correctAnswerPlacemark), true ); connect( d->m_marbleWidget, SIGNAL(highlightedPlacemarksChanged(qreal,qreal,GeoDataCoordinates::Unit)), this, SLOT(determineResult(qreal,qreal,GeoDataCoordinates::Unit)) ); } } // namespace Marble diff --git a/examples/cpp/marble-game/CountryByFlag.cpp b/examples/cpp/marble-game/CountryByFlag.cpp index 5db2ba424..0a3c0f7cc 100644 --- a/examples/cpp/marble-game/CountryByFlag.cpp +++ b/examples/cpp/marble-game/CountryByFlag.cpp @@ -1,174 +1,173 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Abhinav Gangwar // // Self #include "CountryByFlag.h" // Qt #include #include #include #include #include #include // Marble #include #include #include #include #include #include #include #include #include namespace Marble { class CountryByFlagPrivate { public: CountryByFlagPrivate( MarbleWidget *marbleWidget ) : m_marbleWidget( marbleWidget ), m_parent( 0 ), m_countryNames( 0 ) { m_continentsAndOceans << QStringLiteral("Asia") << QStringLiteral("Africa") << QStringLiteral("North America") << QStringLiteral("South America") << QStringLiteral("Antarctica") << QStringLiteral("Europe") << QStringLiteral("Australia") << QStringLiteral("Arctic Ocean") << QStringLiteral("Indian Ocean") << QStringLiteral("North Atlantic Ocean") << QStringLiteral("North Pacific Ocean") << QStringLiteral("South Pacific Ocean") << QStringLiteral("South Atlantic Ocean") << QStringLiteral("Southern Ocean"); } MarbleWidget *m_marbleWidget; CountryByFlag *m_parent; /** * Document to store point placemarks which * have country names ( from file "boundaryplacemarks.cache" ) */ GeoDataDocument *m_countryNames; /* * When I select a random placemark form boundaryplacemarks.cache * it may represent a continent. Since there is no flag * for a continent, we will not use this placemark to post question. * This list will help checking whether the placemark chosen to * post question is a continent/ocean . */ QStringList m_continentsAndOceans; }; CountryByFlag::CountryByFlag( MarbleWidget *marbleWidget ) : QObject(), d ( new CountryByFlagPrivate(marbleWidget) ) { d->m_parent = this; } CountryByFlag::~CountryByFlag() { delete d->m_countryNames; delete d; } void CountryByFlag::initiateGame() { /** * First remove the GeoDataDocument, which displays * country names, from map. */ if ( !d->m_countryNames ) { const GeoDataTreeModel *const treeModel = d->m_marbleWidget->model()->treeModel(); for ( int i = 0; i < treeModel->rowCount(); ++i ) { QVariant const data = treeModel->data ( treeModel->index ( i, 0 ), MarblePlacemarkModel::ObjectPointerRole ); GeoDataObject *object = qvariant_cast( data ); Q_ASSERT_X( object, "CountryByFlag::initiateGame", "failed to get valid data from treeModel for GeoDataObject" ); - if ( object->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - GeoDataDocument *doc = static_cast( object ); + if (auto doc = geodata_cast(object)) { QFileInfo fileInfo( doc->fileName() ); if (fileInfo.fileName() == QLatin1String("boundaryplacemarks.cache")) { d->m_countryNames = doc; break; } } } } if ( d->m_countryNames ) { d->m_countryNames->setVisible( false ); d->m_marbleWidget->model()->treeModel()->updateFeature( d->m_countryNames ); d->m_marbleWidget->centerOn( 23.0, 42.0 ); d->m_marbleWidget->setDistance( 7500 ); d->m_marbleWidget->setHighlightEnabled( false ); emit gameInitialized(); } } void CountryByFlag::postQuestion( QObject *gameObject ) { /** * Find a random placemark */ Q_ASSERT_X( d->m_countryNames, "CountryByFlag::postQuestion", "CountryByFlagPrivate::m_countryNames is NULL" ); QVector countryPlacemarks = d->m_countryNames->placemarkList(); uint randomSeed = uint(QTime::currentTime().msec()); qsrand( randomSeed ); bool found = false; GeoDataPlacemark *placemark = 0; QVariantList answerOptions; QString flagPath; while ( !found ) { int randomIndex = qrand()%countryPlacemarks.size(); placemark = countryPlacemarks[randomIndex]; if ( !d->m_continentsAndOceans.contains(placemark->name(), Qt::CaseSensitive) ) { const QString countryCode = placemark->countryCode().toLower(); flagPath = MarbleDirs::path(QLatin1String("flags/flag_") + countryCode + QLatin1String(".svg")); QImage flag = QFile::exists( flagPath ) ? QImage( flagPath ) : QImage(); if ( !flag.isNull() ) { flagPath = QLatin1String("../../../data/flags/flag_") + countryCode + QLatin1String(".svg"); found = true; } } } answerOptions << placemark->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name(); // Randomize the options in the list answerOptions for ( int i = 0; i < answerOptions.size(); ++i ) { QVariant option = answerOptions.takeAt( qrand()%answerOptions.size() ); answerOptions.append( option ); } if ( gameObject ) { QMetaObject::invokeMethod( gameObject, "countryByFlagQuestion", Q_ARG(QVariant, QVariant(answerOptions)), Q_ARG(QVariant, QVariant(flagPath)), Q_ARG(QVariant, QVariant(placemark->name())) ); } } } // namespace Marble #include "moc_CountryByFlag.cpp" diff --git a/examples/cpp/marble-game/CountryByShape.cpp b/examples/cpp/marble-game/CountryByShape.cpp index f853947de..19094ca98 100644 --- a/examples/cpp/marble-game/CountryByShape.cpp +++ b/examples/cpp/marble-game/CountryByShape.cpp @@ -1,268 +1,265 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Abhinav Gangwar // // Self #include "CountryByShape.h" // Qt #include #include #include #include #include // Marble #include #include #include #include -#include #include #include #include #include #include #include #include #include #include namespace Marble { class CountryByShapePrivate { public: CountryByShapePrivate( MarbleWidget *marbleWidget ) : m_parent( 0 ), m_marbleWidget( marbleWidget ), m_countryNames( 0 ), m_countryBoundaries( 0 ) { m_continentsAndOceans << QStringLiteral("Asia") << QStringLiteral("Africa") << QStringLiteral("North America") << QStringLiteral("South America") << QStringLiteral("Antarctica") << QStringLiteral("Europe") << QStringLiteral("Australia") << QStringLiteral("Arctic Ocean") << QStringLiteral("Indian Ocean") << QStringLiteral("North Atlantic Ocean") << QStringLiteral("North Pacific Ocean") << QStringLiteral("South Pacific Ocean") << QStringLiteral("South Atlantic Ocean") << QStringLiteral("Southern Ocean"); } CountryByShape *m_parent; MarbleWidget *m_marbleWidget; /** * Document to store point placemarks which * have country names ( from file "boundaryplacemarks.cache" ) */ GeoDataDocument *m_countryNames; /** * Document which have placemarks whose geometry * specifies the boundaries of a country * (from file "ne_50m_admin_0_countries.pn2" ) */ GeoDataDocument *m_countryBoundaries; /** * If the placemark, we select from boundaryplacemarks.cache, * is a continent, the game will highlight a country, * on map, which contains this point placemark in its geometry * instead of highlighting the whole continent. * Also, oceans are point placemark and we don't have * any geometry, provided for oceans , that we can highlight. * So, to avoid placemarks which represent continent or ocean * we will use this list. */ QStringList m_continentsAndOceans; }; CountryByShape::CountryByShape( MarbleWidget *marbleWidget ) : QObject(), d( new CountryByShapePrivate(marbleWidget) ) { d->m_parent = this; connect( this, SIGNAL(announceHighlight(qreal,qreal,GeoDataCoordinates::Unit)), d->m_marbleWidget, SIGNAL(highlightedPlacemarksChanged(qreal,qreal,GeoDataCoordinates::Unit)) ); } CountryByShape::~CountryByShape() { delete d; } void CountryByShape::initiateGame() { if ( !d->m_countryNames ) { const GeoDataTreeModel *const treeModel = d->m_marbleWidget->model()->treeModel(); for ( int i = 0; i < treeModel->rowCount(); ++i ) { QVariant const data = treeModel->data ( treeModel->index ( i, 0 ), MarblePlacemarkModel::ObjectPointerRole ); GeoDataObject *object = qvariant_cast( data ); Q_ASSERT_X( object, "CountryByShape::initiateGame", "failed to get valid data from treeModel for GeoDataObject" ); - if ( object->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - GeoDataDocument *doc = static_cast( object ); + if (auto doc = geodata_cast(object)) { QFileInfo fileInfo( doc->fileName() ); if (fileInfo.fileName() == QLatin1String("boundaryplacemarks.cache")) { d->m_countryNames = doc; break; } } } } if ( !d->m_countryBoundaries ) { const GeoDataTreeModel *const treeModel = d->m_marbleWidget->model()->treeModel(); for ( int i = 0; i < treeModel->rowCount(); ++i ) { QVariant const data = treeModel->data ( treeModel->index ( i, 0 ), MarblePlacemarkModel::ObjectPointerRole ); GeoDataObject *object = qvariant_cast( data ); Q_ASSERT_X( object, "MainWindow::initiateGame", "failed to get valid data from treeModel for GeoDataObject" ); - if ( object->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - GeoDataDocument *const doc = static_cast( object ); + if (auto doc = geodata_cast(object)) { QFileInfo fileInfo( doc->fileName() ); if (fileInfo.fileName() == QLatin1String("ne_50m_admin_0_countries.pn2")) { d->m_countryBoundaries = doc; break; } } } } d->m_marbleWidget->setHighlightEnabled( true ); if ( d->m_countryBoundaries && d->m_countryNames ) { d->m_countryNames->setVisible( false ); d->m_marbleWidget->model()->treeModel()->updateFeature( d->m_countryNames ); emit gameInitialized(); } } void CountryByShape::postQuestion( QObject *gameObject ) { //Find a random placemark Q_ASSERT_X( d->m_countryNames, "CountryByShape::postQuestion", "CountryByShapePrivate::m_countryNames is NULL" ); QVector countryPlacemarks = d->m_countryNames->placemarkList(); uint randomSeed = uint(QTime::currentTime().msec()); qsrand( randomSeed ); bool found = false; GeoDataPlacemark *placemark =0; GeoDataPoint *point = 0; GeoDataCoordinates coord; GeoDataLatLonAltBox box; QVariantList answerOptions; while ( !found ) { int randomIndex = qrand()%countryPlacemarks.size(); placemark = countryPlacemarks[randomIndex]; point = dynamic_cast( placemark->geometry() ); coord = point->coordinates(); if ( point ) { /** * Find the country geometry and fetch corresponding * GeoDataLatLonAltBox to zoom in to that country so that * it fills the viewport. */ Q_ASSERT_X( d->m_countryBoundaries, "CountryByShape::postQuestion", "CountryByShapePrivate::m_countryBoundaries is NULL" ); QVector::Iterator i = d->m_countryBoundaries->begin(); QVector::Iterator const end = d->m_countryBoundaries->end(); for ( ; i != end; ++i ) { GeoDataPlacemark *country = static_cast( *i ); GeoDataPolygon *polygon = dynamic_cast( country->geometry() ); GeoDataLinearRing *linearring = dynamic_cast( country->geometry() ); GeoDataMultiGeometry *multigeom = dynamic_cast( country->geometry() ); if ( polygon && polygon->contains( coord ) && !d->m_continentsAndOceans.contains(country->name(), Qt::CaseSensitive) ) { box = polygon->latLonAltBox(); found = true; break; } if ( linearring && linearring->contains( coord ) && !d->m_continentsAndOceans.contains(country->name(), Qt::CaseSensitive) ) { box = linearring->latLonAltBox(); found = true; break; } if ( multigeom ) { QVector::Iterator iter = multigeom->begin(); QVector::Iterator const end = multigeom->end(); for ( ; iter != end; ++iter ) { GeoDataPolygon *poly = dynamic_cast( *iter ); if ( poly && poly->contains( coord ) && !d->m_continentsAndOceans.contains(country->name(), Qt::CaseSensitive) ) { box = poly->latLonAltBox(); found = true; break; } } } if ( found ) { break; } } } } d->m_marbleWidget->setHighlightEnabled( true ); emit announceHighlight( coord.longitude(GeoDataCoordinates::Degree), coord.latitude(GeoDataCoordinates::Degree), GeoDataCoordinates::Degree ); /** * Now disable the highlight feature so that * the user click doesn't disturbe the highlight * we did to ask question. */ d->m_marbleWidget->setHighlightEnabled( false ); d->m_marbleWidget->centerOn( box, true ); answerOptions << placemark->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name() << countryPlacemarks[qrand()%countryPlacemarks.size()]->name(); // Randomize options in list answerOptions for ( int i = 0; i < answerOptions.size(); ++i ) { QVariant option = answerOptions.takeAt( qrand()%answerOptions.size() ); answerOptions.append( option ); } if ( gameObject ) { QMetaObject::invokeMethod( gameObject, "countryByShapeQuestion", Q_ARG(QVariant, QVariant(answerOptions)), Q_ARG(QVariant, QVariant(placemark->name())) ); } } } // namespace Marble #include "moc_CountryByShape.cpp" diff --git a/examples/cpp/marble-game/GameMainWindow.cpp b/examples/cpp/marble-game/GameMainWindow.cpp index 0549ea433..4c6aa0b58 100644 --- a/examples/cpp/marble-game/GameMainWindow.cpp +++ b/examples/cpp/marble-game/GameMainWindow.cpp @@ -1,288 +1,286 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Dennis Nienhüser // Copyright 2014 Abhinav Gangwar // // Self #include "GameMainWindow.h" #include "CountryByShape.h" #include "CountryByFlag.h" #include "ClickOnThat.h" #include "ui_game.h" // Qt #include #include #include #include #include #include #include #include #include #include #include // Marble #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include namespace Marble { class Private : public Ui_MainWindow { public: Private( QWidget *parent = 0 ); MarbleWidget *m_marbleWidget; QWidget *m_parent; QQuickView m_view; CountryByShape *m_countryByShape; CountryByFlag *m_countryByFlag; ClickOnThat *m_clickOnThat; QString readMarbleDataPath() const; void setupMarbleWidget(); void setupGameSignals(); }; Private::Private(QWidget* parent) : m_marbleWidget( new MarbleWidget( parent ) ), m_parent( parent ), m_view(), m_countryByShape( new CountryByShape(m_marbleWidget) ), m_countryByFlag( new CountryByFlag(m_marbleWidget) ), m_clickOnThat( new ClickOnThat(m_marbleWidget) ) { // nothing to do } QString Private::readMarbleDataPath() const { return QSettings().value(QStringLiteral("MarbleWidget/marbleDataPath"), QString()).toString(); } void Private::setupMarbleWidget() { m_marbleWidget->setMapThemeId(QStringLiteral( "earth/political/political.dgml")); foreach ( RenderPlugin *renderPlugin, m_marbleWidget->renderPlugins() ) { if (renderPlugin->nameId() == QLatin1String("stars") || renderPlugin->nameId() == QLatin1String("overviewmap") || renderPlugin->nameId() == QLatin1String("compass") || renderPlugin->nameId() == QLatin1String("scalebar") || renderPlugin->nameId() == QLatin1String("navigation")) { renderPlugin->setVisible( false ); } } m_marbleWidget->centerOn( 23.0, 42.0 ); m_marbleWidget->setDistance( 7500 ); m_parent->connect( m_parent, SIGNAL(announceHighlight(qreal,qreal,GeoDataCoordinates::Unit)), m_marbleWidget, SIGNAL(highlightedPlacemarksChanged(qreal,qreal,GeoDataCoordinates::Unit)) ); } void Private::setupGameSignals() { QObject *root = m_view.rootObject(); if ( root ) { m_parent->connect( root, SIGNAL(browseMapButtonClicked()), m_parent, SLOT(browseMapButtonClicked()) ); QObject *gameOptions = root->findChild(QStringLiteral("gameOptions")); m_parent->connect( gameOptions, SIGNAL(nextButtonClicked()), m_parent, SLOT(createQuestion()) ); m_parent->connect( gameOptions, SIGNAL(gameClosed()), m_parent, SLOT(disableGames()) ); // For "Identify the highlighted country" game m_parent->connect( gameOptions, SIGNAL(countryByShapeGameRequested()), m_parent, SLOT(enableCountryShapeGame()) ); m_parent->connect( m_countryByShape, SIGNAL(gameInitialized()), m_parent, SLOT(createQuestion()) ); // For "Identify the flag" game m_parent->connect( gameOptions, SIGNAL(countryByFlagGameRequested()), m_parent, SLOT(enableCountryFlagGame()) ); m_parent->connect( m_countryByFlag, SIGNAL(gameInitialized()), m_parent, SLOT(createQuestion()) ); // For "Click on that country" game m_parent->connect( gameOptions, SIGNAL(clickOnThatGameRequested()), m_parent, SLOT(enableClickOnThatGame()) ); m_parent->connect( m_clickOnThat, SIGNAL(gameInitialized()), m_parent, SLOT(createQuestion()) ); m_parent->connect( gameOptions, SIGNAL(answerDisplayButtonClicked()), m_clickOnThat, SLOT(highlightCorrectAnswer()) ); } } MainWindow::MainWindow( const QString &marbleDataPath, QWidget *parent, Qt::WindowFlags flags ) : QMainWindow( parent, flags ), d( new Private( this ) ) { d->setupUi( this ); QString const dataPath = marbleDataPath.isEmpty() ? d->readMarbleDataPath() : marbleDataPath; if ( !dataPath.isEmpty() ) { MarbleDirs::setMarbleDataPath( dataPath ); } d->setupMarbleWidget(); setCentralWidget( d->m_marbleWidget ); d->m_view.setSource(QUrl(QStringLiteral("qrc:/Window.qml"))); QWidget *leftPanel = QWidget::createWindowContainer( &d->m_view, d->dockWidgetContents ); QVBoxLayout *layout = new QVBoxLayout( d->dockWidgetContents ); layout->addWidget( leftPanel ); d->dockWidgetContents->setLayout( layout ); d->setupGameSignals(); } MainWindow::~MainWindow() { delete d; } MarbleWidget *MainWindow::marbleWidget() { return d->m_marbleWidget; } void MainWindow::createQuestion() { QObject *gameObject = d->m_view.rootObject()->findChild(QStringLiteral("gameOptions")); if ( gameObject ) { emit postQuestion( gameObject ); } } void MainWindow::browseMapButtonClicked() { d->m_marbleWidget->setMapThemeId(QStringLiteral("earth/political/political.dgml")); /** * Now display the country names which * were removed to initiate the game */ const GeoDataTreeModel *const treeModel = d->m_marbleWidget->model()->treeModel(); for ( int i = 0; i < treeModel->rowCount(); ++i ) { QVariant const data = treeModel->data ( treeModel->index ( i, 0 ), MarblePlacemarkModel::ObjectPointerRole ); GeoDataObject *object = qvariant_cast( data ); Q_ASSERT_X( object, "MainWindow::browseMapButtonClicked", "failed to get valid data from treeModel for GeoDataObject" ); - if ( object->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - GeoDataDocument *doc = static_cast( object ); + if (auto doc = geodata_cast(object)) { QFileInfo fileInfo( doc->fileName() ); QString fileName = fileInfo.fileName(); if (fileName == QLatin1String("boundaryplacemarks.cache")) { doc->setVisible( true ); d->m_marbleWidget->model()->treeModel()->updateFeature( doc ); d->m_marbleWidget->setHighlightEnabled( true ); break; } } } } void MainWindow::disableGames() { disconnect( this, SIGNAL(postQuestion(QObject*)), d->m_countryByShape, SLOT(postQuestion(QObject*)) ); disconnect( this, SIGNAL(postQuestion(QObject*)), d->m_countryByFlag, SLOT(postQuestion(QObject*)) ); disconnect( this, SIGNAL(postQuestion(QObject*)), d->m_clickOnThat, SLOT(postQuestion(QObject*)) ); disconnect( d->m_clickOnThat, SIGNAL(updateResult(bool)), this, SLOT(displayResult(bool)) ); disconnect( d->m_marbleWidget, SIGNAL(highlightedPlacemarksChanged(qreal,qreal,GeoDataCoordinates::Unit)), d->m_clickOnThat, SLOT(determineResult(qreal,qreal,GeoDataCoordinates::Unit)) ); d->m_clickOnThat->disablePinDocument(); // Reset the map view d->m_marbleWidget->centerOn( 23.0, 42.0 ); d->m_marbleWidget->setDistance( 7500 ); } void MainWindow::enableCountryShapeGame() { connect( this, SIGNAL(postQuestion(QObject*)), d->m_countryByShape, SLOT(postQuestion(QObject*)) ); d->m_countryByShape->initiateGame(); } void MainWindow::enableCountryFlagGame() { connect( this, SIGNAL(postQuestion(QObject*)), d->m_countryByFlag, SLOT(postQuestion(QObject*)) ); d->m_countryByFlag->initiateGame(); } void MainWindow::enableClickOnThatGame() { connect( this, SIGNAL(postQuestion(QObject*)), d->m_clickOnThat, SLOT(postQuestion(QObject*)) ); connect( d->m_clickOnThat, SIGNAL(updateResult(bool)), this, SLOT(displayResult(bool)) ); d->m_clickOnThat->initiateGame(); } void MainWindow::displayResult(bool result ) { QObject *gameObject = d->m_view.rootObject()->findChild(QStringLiteral("gameOptions")); if ( gameObject ) { QMetaObject::invokeMethod( gameObject, "displayResult", Q_ARG(QVariant, QVariant(result)) ); } } /* * As the height of main window is changed, update the * height ( leftPanelHeight ) in window.qml */ void MainWindow::resizeEvent(QResizeEvent* event) { const QSize size = event->size(); QObject *root = d->m_view.rootObject(); if ( root ) { QMetaObject::invokeMethod( root, "resizeWindow", Q_ARG(QVariant, QVariant(size.height()*9/10)) ); } } } // namespace Marble #include "moc_GameMainWindow.cpp" diff --git a/examples/cpp/squad-interpolation/squad-interpolation.cpp b/examples/cpp/squad-interpolation/squad-interpolation.cpp index 77cbf3d6d..ee26a90db 100644 --- a/examples/cpp/squad-interpolation/squad-interpolation.cpp +++ b/examples/cpp/squad-interpolation/squad-interpolation.cpp @@ -1,243 +1,241 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Dennis Nienhüser // #include "squad-interpolation.h" #include #include #include #include #include #include #include #include #include -#include #include #include #include #include namespace Marble { MyPaintLayer::MyPaintLayer ( MarbleWidget *widget ) : m_widget ( widget ), m_fraction ( 0.0 ), m_delta( 0.02 ), m_index ( 0 ) { GeoDataCoordinates::Unit const degree = GeoDataCoordinates::Degree; m_cities << GeoDataCoordinates( 7.64573, 45.04981, 0.0, degree ); // Torino m_cities << GeoDataCoordinates( 8.33439, 49.01673, 0.0, degree ); // Karlsruhe m_cities << GeoDataCoordinates( 14.41637, 50.09329, 0.0, degree ); // Praha m_cities << GeoDataCoordinates( 15.97254, 45.80268, 0.0, degree ); // Zagred addInterpolatedPoint(); } QStringList MyPaintLayer::renderPosition() const { return QStringList(QStringLiteral("USER_TOOLS")); } bool MyPaintLayer::render ( GeoPainter *painter, ViewportParams *viewport, const QString &, GeoSceneLayer * ) { if ( m_index < 20 ) { // Gray dotted line connects all current cities QPen grayPen = Marble::Oxygen::aluminumGray4; grayPen.setWidth ( 3 ); grayPen.setStyle ( Qt::DotLine ); painter->setPen ( grayPen ); painter->drawPolyline ( m_cities ); } // Blue circle around each city painter->setBrush ( QBrush ( QColor ( Marble::Oxygen::skyBlue4 ) ) ); painter->setPen ( QColor ( Marble::Oxygen::aluminumGray4 ) ); for ( int i = 0; i < m_cities.size(); ++i ) { painter->drawEllipse ( m_cities[i], 32, 32 ); } if (m_index < 10) { // Show how squad interpolation works internally Q_ASSERT( m_cities.size() == 4 ); painter->setBrush ( QBrush ( QColor ( Marble::Oxygen::grapeViolet4 ) ) ); painter->setPen ( QColor ( Marble::Oxygen::aluminumGray4 ) ); GeoDataCoordinates a2 = basePoint( m_cities[0], m_cities[1], m_cities[2] ); painter->drawEllipse ( a2, 8, 8 ); qreal x, y; if ( viewport->screenCoordinates ( a2, x, y ) ) { painter->drawText(x+5, y, QStringLiteral("A")); } GeoDataCoordinates b1 = basePoint( m_cities[1], m_cities[2], m_cities[3] ); painter->drawEllipse ( b1, 8, 8 ); if ( viewport->screenCoordinates ( b1, x, y ) ) { painter->drawText(x+5, y, QStringLiteral("B")); } QPen grapePen = Marble::Oxygen::grapeViolet4; grapePen.setWidth ( 2 ); painter->setPen ( grapePen ); GeoDataLineString string; string << m_cities[0] << a2 << b1 << m_cities[3]; painter->drawPolyline ( string ); GeoDataCoordinates i1 = m_cities[1].interpolate( m_cities[2], m_fraction-m_delta ); GeoDataCoordinates i2 = a2.interpolate( b1, m_fraction-m_delta ); QPen raspberryPen = Marble::Oxygen::burgundyPurple4; raspberryPen.setWidth ( 2 ); painter->setPen ( raspberryPen ); GeoDataLineString inter; inter << i1 << i2; painter->drawPolyline ( inter ); } // Green linestring shows interpolation path QPen greenPen = Marble::Oxygen::forestGreen4; greenPen.setWidth ( 3 ); painter->setPen ( greenPen ); painter->drawPolyline ( m_interpolated, QStringLiteral("Squad\nInterpolation"), LineEnd ); // Increasing city indices with some transparency effect for readability QFont font = painter->font(); font.setBold( true ); painter->setFont( font ); QColor blue = QColor ( Marble::Oxygen::skyBlue4 ); blue.setAlpha( 150 ); painter->setBrush ( QBrush ( blue ) ); int const h = painter->fontMetrics().height(); for ( int i = 0; i < m_cities.size(); ++i ) { qreal x, y; QString const text = QString::number ( m_index + i ); int const w = painter->fontMetrics().width( text ); painter->setPen ( Qt::NoPen ); painter->drawEllipse ( m_cities[i], 1.5*w, 1.5*h ); painter->setPen ( QColor ( Marble::Oxygen::aluminumGray4 ) ); if ( viewport->screenCoordinates ( m_cities[i], x, y ) ) { painter->drawText ( x-w/2, y+h/3, text ); } } return true; } GeoDataLatLonBox MyPaintLayer::center() const { GeoDataLinearRing ring; foreach( const GeoDataCoordinates &city, m_cities ) { ring << city; } return ring.latLonAltBox(); } void MyPaintLayer::addRandomCity ( double minDistance, double maxDistance ) { minDistance *= KM2METER; maxDistance *= KM2METER; GeoDataTreeModel* tree = m_widget->model()->treeModel(); if ( !tree || tree->rowCount() < 6 || m_cities.isEmpty() ) { return; } // Traverse Marble's internal city database and add a random one // which is in the requested distance range to the last one for ( int i = 0; i < tree->rowCount(); ++i ) { QVariant const data = tree->data ( tree->index ( i, 0 ), MarblePlacemarkModel::ObjectPointerRole ); GeoDataObject *object = qvariant_cast ( data ); Q_ASSERT ( object ); - if ( object->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - GeoDataDocument* document = static_cast ( object ); + if (const auto document = geodata_cast(object)) { if (document->name() == QLatin1String("cityplacemarks")) { QVector placemarks = document->placemarkList(); for ( int i = qrand() % placemarks.size(); i < placemarks.size(); ++i ) { double const distance = EARTH_RADIUS * distanceSphere ( m_cities.last(), placemarks[i]->coordinate() ); if ( distance >= minDistance && distance <= maxDistance ) { m_cities << placemarks[i]->coordinate(); return; } } } } } addRandomCity(); } GeoDataCoordinates MyPaintLayer::basePoint( const GeoDataCoordinates &c1, const GeoDataCoordinates &c2, const GeoDataCoordinates &c3 ) { Quaternion const a = (c2.quaternion().inverse() * c3.quaternion()).log(); Quaternion const b = (c2.quaternion().inverse() * c1.quaternion()).log(); Quaternion const c = c2.quaternion() * ((a+b)*-0.25).exp(); qreal lon, lat; c.getSpherical( lon, lat ); return GeoDataCoordinates( lon, lat ); } void MyPaintLayer::addInterpolatedPoint() { while ( m_interpolated.size() > 2.0/m_delta ) { m_interpolated.remove ( 0 ); } m_delta = m_index < 20 ? 0.01 : 0.04; Q_ASSERT ( m_cities.size() == 4 ); // Interpolate for the current city m_interpolated << m_cities[1].interpolate ( m_cities[0], m_cities[2], m_cities[3], m_fraction ); m_fraction += m_delta; // If current city is done, move one forward if ( m_fraction > 1.0 ) { m_fraction = 0.0; m_cities.remove ( 0 ); addRandomCity(); ++m_index; } // Repaint map, recenter if out of view bool hidden; qreal x; qreal y; if ( m_widget->viewport()->screenCoordinates ( m_interpolated.last(), x, y, hidden ) ) { m_widget->update(); } else { m_widget->centerOn ( center() ); } int const timeout = qBound( 0, 150 - 50 * m_index, 150 ); QTimer::singleShot ( timeout, this, SLOT (addInterpolatedPoint()) ); } } int main ( int argc, char** argv ) { using namespace Marble; QApplication app ( argc, argv ); MarbleWidget *mapWidget = new MarbleWidget; mapWidget->setWindowTitle(QStringLiteral("Marble - Squad Interpolation")); // Create and register our paint layer MyPaintLayer* layer = new MyPaintLayer ( mapWidget ); mapWidget->addLayer ( layer ); mapWidget->centerOn ( layer->center() ); // Finish widget creation. mapWidget->setMapThemeId(QStringLiteral("earth/plain/plain.dgml")); mapWidget->setShowCities( false ); mapWidget->setShowCrosshairs( false ); mapWidget->setShowOtherPlaces( false ); mapWidget->setShowPlaces( false ); mapWidget->setShowTerrain( false ); mapWidget->show(); return app.exec(); } #include "moc_squad-interpolation.cpp" diff --git a/src/lib/marble/FileLoader.cpp b/src/lib/marble/FileLoader.cpp index 4bb194010..a531a0000 100644 --- a/src/lib/marble/FileLoader.cpp +++ b/src/lib/marble/FileLoader.cpp @@ -1,566 +1,567 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2008 Patrick Spendrin // #include "FileLoader.h" #include #include #include #include #include "GeoDataParser.h" #include "GeoDataDocument.h" #include "GeoDataFolder.h" +#include "GeoDataGroundOverlay.h" #include "GeoDataPlacemark.h" #include "GeoDataData.h" #include "GeoDataExtendedData.h" #include "GeoDataStyle.h" #include "GeoDataStyleMap.h" +#include "GeoDataPhotoOverlay.h" +#include "GeoDataPoint.h" #include "GeoDataPolyStyle.h" #include "GeoDataLineStyle.h" #include "GeoDataPolygon.h" -#include "GeoDataTypes.h" +#include "GeoDataScreenOverlay.h" +#include "GeoDataTour.h" +#include "GeoDataTrack.h" #include "MarbleDirs.h" #include "MarbleDebug.h" #include "MarbleModel.h" #include "ParsingRunnerManager.h" namespace Marble { class FileLoaderPrivate { public: FileLoaderPrivate( FileLoader* parent, const PluginManager *pluginManager, bool recenter, const QString& file, const QString& property, const GeoDataStyle::Ptr &style, DocumentRole role, int renderOrder ) : q( parent), m_runner( pluginManager ), m_recenter( recenter ), m_filepath ( file ), m_property( property ), m_style( style ), m_documentRole ( role ), m_styleMap( new GeoDataStyleMap ), m_document( 0 ), m_renderOrder( renderOrder ) { if( m_style ) { m_styleMap->setId(QStringLiteral("default-map")); m_styleMap->insert(QStringLiteral("normal"), QLatin1Char('#') + m_style->id()); } } FileLoaderPrivate( FileLoader* parent, const PluginManager *pluginManager, const QString& contents, const QString& file, DocumentRole role ) : q( parent ), m_runner( pluginManager ), m_recenter( false ), m_filepath ( file ), m_contents ( contents ), m_documentRole ( role ), m_styleMap( 0 ), m_document( 0 ) { } ~FileLoaderPrivate() { delete m_styleMap; } void createFilterProperties( GeoDataContainer *container ); static int cityPopIdx( qint64 population ); static int spacePopIdx( qint64 population ); static int areaPopIdx( qreal area ); void documentParsed( GeoDataDocument *doc, const QString& error); FileLoader *q; ParsingRunnerManager m_runner; bool m_recenter; QString m_filepath; QString m_contents; QString m_property; GeoDataStyle::Ptr m_style; DocumentRole m_documentRole; GeoDataStyleMap* m_styleMap; GeoDataDocument *m_document; QString m_error; int m_renderOrder; }; FileLoader::FileLoader( QObject* parent, const PluginManager *pluginManager, bool recenter, const QString& file, const QString& property, const GeoDataStyle::Ptr &style, DocumentRole role, int renderOrder ) : QThread( parent ), d( new FileLoaderPrivate( this, pluginManager, recenter, file, property, style, role, renderOrder ) ) { } FileLoader::FileLoader( QObject* parent, const PluginManager *pluginManager, const QString& contents, const QString& file, DocumentRole role ) : QThread( parent ), d( new FileLoaderPrivate( this, pluginManager, contents, file, role ) ) { } FileLoader::~FileLoader() { delete d; } QString FileLoader::path() const { return d->m_filepath; } GeoDataDocument* FileLoader::document() { return d->m_document; } QString FileLoader::error() const { return d->m_error; } void FileLoader::run() { if ( d->m_contents.isEmpty() ) { QString defaultSourceName; mDebug() << "starting parser for" << d->m_filepath; QFileInfo fileinfo( d->m_filepath ); QString path = fileinfo.path(); if (path == QLatin1String(".")) path.clear(); QString name = fileinfo.completeBaseName(); QString suffix = fileinfo.suffix(); // determine source, cache names if ( fileinfo.isAbsolute() ) { // We got an _absolute_ path now: e.g. "/patrick.kml" defaultSourceName = path + QLatin1Char('/') + name + QLatin1Char('.') + suffix; } else if ( d->m_filepath.contains( '/' ) ) { // _relative_ path: "maps/mars/viking/patrick.kml" defaultSourceName = MarbleDirs::path(path + QLatin1Char('/') + name + QLatin1Char('.') + suffix); if ( !QFile::exists( defaultSourceName ) ) { defaultSourceName = MarbleDirs::path(path + QLatin1Char('/') + name + QLatin1String(".cache")); } } else { // _standard_ shared placemarks: "placemarks/patrick.kml" defaultSourceName = MarbleDirs::path(QLatin1String("placemarks/") + path + name + QLatin1Char('.') + suffix); if ( !QFile::exists( defaultSourceName ) ) { defaultSourceName = MarbleDirs::path(QLatin1String("placemarks/") + path + name + QLatin1String(".cache")); } } if ( QFile::exists( defaultSourceName ) ) { mDebug() << "No recent Default Placemark Cache File available!"; // use runners: pnt, gpx, osm connect( &d->m_runner, SIGNAL(parsingFinished(GeoDataDocument*,QString)), this, SLOT(documentParsed(GeoDataDocument*,QString)) ); d->m_runner.parseFile( defaultSourceName, d->m_documentRole ); } else { mDebug() << "No Default Placemark Source File for " << name; } // content is not empty, we load from data } else { // Read the KML Data GeoDataParser parser( GeoData_KML ); QByteArray ba( d->m_contents.toUtf8() ); QBuffer buffer( &ba ); buffer.open( QIODevice::ReadOnly ); if ( !parser.read( &buffer ) ) { qWarning( "Could not import kml buffer!" ); emit loaderFinished( this ); return; } GeoDocument* document = parser.releaseDocument(); Q_ASSERT( document ); d->m_document = static_cast( document ); d->m_document->setProperty( d->m_property ); d->m_document->setDocumentRole( d->m_documentRole ); d->createFilterProperties( d->m_document ); buffer.close(); mDebug() << "newGeoDataDocumentAdded" << d->m_filepath; emit newGeoDataDocumentAdded( d->m_document ); emit loaderFinished( this ); } } bool FileLoader::recenter() const { return d->m_recenter; } void FileLoaderPrivate::documentParsed( GeoDataDocument* doc, const QString& error ) { m_error = error; if ( doc ) { m_document = doc; doc->setProperty( m_property ); if( m_style ) { doc->addStyleMap( *m_styleMap ); doc->addStyle( m_style ); } if (m_renderOrder != 0) { for (GeoDataPlacemark* placemark: doc->placemarkList()) { - if (placemark->geometry() && placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) { - GeoDataPolygon *polygon = static_cast(placemark->geometry()); + if (GeoDataPolygon *polygon = geodata_cast(placemark->geometry())) { polygon->setRenderOrder(m_renderOrder); } } } createFilterProperties( doc ); emit q->newGeoDataDocumentAdded( m_document ); } emit q->loaderFinished( q ); } void FileLoaderPrivate::createFilterProperties( GeoDataContainer *container ) { const QString styleUrl = QLatin1Char('#') + m_styleMap->id(); QVector::Iterator i = container->begin(); QVector::Iterator const end = container->end(); for (; i != end; ++i ) { if (auto child = dynamic_cast(*i)) { createFilterProperties( child ); - } else if ( (*i)->nodeType() == GeoDataTypes::GeoDataTourType - || (*i)->nodeType() == GeoDataTypes::GeoDataGroundOverlayType - || (*i)->nodeType() == GeoDataTypes::GeoDataPhotoOverlayType - || (*i)->nodeType() == GeoDataTypes::GeoDataScreenOverlayType ) { + } else if (geodata_cast(*i) + || geodata_cast(*i) + || geodata_cast(*i) + || geodata_cast(*i)) { /** @todo: How to handle this ? */ - } else if ( (*i)->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - Q_ASSERT( dynamic_cast( *i ) ); - - GeoDataPlacemark* placemark = static_cast( *i ); + } else if (auto placemark = geodata_cast(*i)) { const QString placemarkRole = placemark->role(); Q_ASSERT( placemark->geometry() ); bool hasPopularity = false; - if ( placemark->geometry()->nodeType() != GeoDataTypes::GeoDataTrackType && - placemark->geometry()->nodeType() != GeoDataTypes::GeoDataPointType + if (!geodata_cast(placemark->geometry()) && + !geodata_cast(placemark->geometry()) && m_documentRole == MapDocument && m_style ) { placemark->setStyleUrl(styleUrl); } // Mountain (H), Volcano (V), Shipwreck (W) if (placemarkRole == QLatin1String("H") || placemarkRole == QLatin1String("V") || placemarkRole == QLatin1String("W")) { qreal altitude = placemark->coordinate().altitude(); if ( altitude != 0.0 ) { hasPopularity = true; placemark->setPopularity( (qint64)(altitude * 1000.0) ); placemark->setZoomLevel( cityPopIdx( qAbs( (qint64)(altitude * 1000.0) ) ) ); } } // Continent (K), Ocean (O), Nation (S) else if (placemarkRole == QLatin1String("K") || placemarkRole == QLatin1String("O") || placemarkRole == QLatin1String("S")) { qreal area = placemark->area(); if ( area >= 0.0 ) { hasPopularity = true; // mDebug() << placemark->name() << " " << (qint64)(area); placemark->setPopularity( (qint64)(area * 100) ); placemark->setZoomLevel( areaPopIdx( area ) ); } } // Pole (P) else if (placemarkRole == QLatin1String("P") ) { placemark->setPopularity( 1000000000 ); placemark->setZoomLevel( 1 ); } // Magnetic Pole (M) else if (placemarkRole == QLatin1String("M")) { placemark->setPopularity( 10000000 ); placemark->setZoomLevel( 3 ); } // MannedLandingSite (h) else if (placemarkRole == QLatin1String("h")) { placemark->setPopularity( 1000000000 ); placemark->setZoomLevel( 1 ); } // RoboticRover (r) else if (placemarkRole == QLatin1String("r")) { placemark->setPopularity( 10000000 ); placemark->setZoomLevel( 2 ); } // UnmannedSoftLandingSite (u) else if (placemarkRole == QLatin1String("u")) { placemark->setPopularity( 1000000 ); placemark->setZoomLevel( 3 ); } // UnmannedSoftLandingSite (i) else if (placemarkRole == QLatin1String("i")) { placemark->setPopularity( 1000000 ); placemark->setZoomLevel( 3 ); } // Space Terrain: Craters, Maria, Montes, Valleys, etc. else if (placemarkRole == QLatin1String("m") || placemarkRole == QLatin1String("v") || placemarkRole == QLatin1String("o") || placemarkRole == QLatin1String("c") || placemarkRole == QLatin1String("a")) { qint64 diameter = placemark->population(); if ( diameter >= 0 ) { hasPopularity = true; placemark->setPopularity( diameter ); if (placemarkRole == QLatin1String("c")) { placemark->setZoomLevel( spacePopIdx( diameter ) ); if (placemark->name() == QLatin1String("Tycho") || placemark->name() == QLatin1String("Copernicus")) { placemark->setZoomLevel( 1 ); } } else { placemark->setZoomLevel( spacePopIdx( diameter ) ); } if (placemarkRole == QLatin1String("a") && diameter == 0) { placemark->setPopularity( 1000000000 ); placemark->setZoomLevel( 1 ); } } } else { qint64 population = placemark->population(); if ( population >= 0 ) { hasPopularity = true; placemark->setPopularity( population ); placemark->setZoomLevel( cityPopIdx( population ) ); } } // Then we set the visual category: if (placemarkRole == QLatin1String("H")) placemark->setVisualCategory( GeoDataPlacemark::Mountain ); else if (placemarkRole == QLatin1String("V")) placemark->setVisualCategory( GeoDataPlacemark::Volcano ); else if (placemarkRole == QLatin1String("m")) placemark->setVisualCategory( GeoDataPlacemark::Mons ); else if (placemarkRole == QLatin1String("v")) placemark->setVisualCategory( GeoDataPlacemark::Valley ); else if (placemarkRole == QLatin1String("o")) placemark->setVisualCategory( GeoDataPlacemark::OtherTerrain ); else if (placemarkRole == QLatin1String("c")) placemark->setVisualCategory( GeoDataPlacemark::Crater ); else if (placemarkRole == QLatin1String("a")) placemark->setVisualCategory( GeoDataPlacemark::Mare ); else if (placemarkRole == QLatin1String("P")) placemark->setVisualCategory( GeoDataPlacemark::GeographicPole ); else if (placemarkRole == QLatin1String("M")) placemark->setVisualCategory( GeoDataPlacemark::MagneticPole ); else if (placemarkRole == QLatin1String("W")) placemark->setVisualCategory( GeoDataPlacemark::ShipWreck ); else if (placemarkRole == QLatin1String("F")) placemark->setVisualCategory( GeoDataPlacemark::AirPort ); else if (placemarkRole == QLatin1String("A")) placemark->setVisualCategory( GeoDataPlacemark::Observatory ); else if (placemarkRole == QLatin1String("K")) placemark->setVisualCategory( GeoDataPlacemark::Continent ); else if (placemarkRole == QLatin1String("O")) placemark->setVisualCategory( GeoDataPlacemark::Ocean ); else if (placemarkRole == QLatin1String("S")) placemark->setVisualCategory( GeoDataPlacemark::Nation ); else if (placemarkRole == QLatin1String("PPL") || placemarkRole == QLatin1String("PPLF") || placemarkRole == QLatin1String("PPLG") || placemarkRole == QLatin1String("PPLL") || placemarkRole == QLatin1String("PPLQ") || placemarkRole == QLatin1String("PPLR") || placemarkRole == QLatin1String("PPLS") || placemarkRole == QLatin1String("PPLW")) { switch (placemark->zoomLevel()) { case 3: case 4: placemark->setVisualCategory(GeoDataPlacemark::LargeCity); break; case 5: case 6: placemark->setVisualCategory(GeoDataPlacemark::BigCity); break; case 7: case 8: placemark->setVisualCategory(GeoDataPlacemark::MediumCity); break; default: placemark->setVisualCategory(GeoDataPlacemark::SmallCity); break; } } else if (placemarkRole == QLatin1String("PPLA")) { switch (placemark->zoomLevel()) { case 3: case 4: placemark->setVisualCategory(GeoDataPlacemark::LargeStateCapital); break; case 5: case 6: placemark->setVisualCategory(GeoDataPlacemark::BigStateCapital); break; case 7: case 8: placemark->setVisualCategory(GeoDataPlacemark::MediumStateCapital); break; default: placemark->setVisualCategory(GeoDataPlacemark::SmallStateCapital); break; } } else if (placemarkRole == QLatin1String("PPLC")) { switch (placemark->zoomLevel()) { case 3: case 4: placemark->setVisualCategory(GeoDataPlacemark::LargeNationCapital); break; case 5: case 6: placemark->setVisualCategory(GeoDataPlacemark::BigNationCapital); break; case 7: case 8: placemark->setVisualCategory(GeoDataPlacemark::MediumNationCapital); break; default: placemark->setVisualCategory(GeoDataPlacemark::SmallNationCapital); break; } } else if (placemarkRole == QLatin1String("PPLA2") || placemarkRole == QLatin1String("PPLA3") || placemarkRole == QLatin1String("PPLA4")) { switch (placemark->zoomLevel()) { case 3: case 4: placemark->setVisualCategory(GeoDataPlacemark::LargeCountyCapital); break; case 5: case 6: placemark->setVisualCategory(GeoDataPlacemark::BigCountyCapital); break; case 7: case 8: placemark->setVisualCategory(GeoDataPlacemark::MediumCountyCapital); break; default: placemark->setVisualCategory(GeoDataPlacemark::SmallCountyCapital); break; } } else if (placemarkRole == QLatin1String(" ") && !hasPopularity && placemark->visualCategory() == GeoDataPlacemark::Unknown) { placemark->setVisualCategory( GeoDataPlacemark::Unknown ); // default location placemark->setZoomLevel(0); } else if (placemarkRole == QLatin1String("h")) { placemark->setVisualCategory( GeoDataPlacemark::MannedLandingSite ); } else if (placemarkRole == QLatin1String("r")) { placemark->setVisualCategory( GeoDataPlacemark::RoboticRover ); } else if (placemarkRole == QLatin1String("u")) { placemark->setVisualCategory( GeoDataPlacemark::UnmannedSoftLandingSite ); } else if (placemarkRole == QLatin1String("i")) { placemark->setVisualCategory( GeoDataPlacemark::UnmannedHardLandingSite ); } // At last fine-tune zoomlevel: if (!placemark->isVisible()) { placemark->setZoomLevel( 18 ); } // Workaround: Emulate missing "setVisible" serialization by allowing for population // values smaller than -1 which are considered invisible. else if (placemark->population() < -1) { placemark->setZoomLevel( 18 ); } else if (placemarkRole == QLatin1String("W")) { if (placemark->zoomLevel() < 4) { placemark->setZoomLevel( 4 ); } } else if (placemarkRole == QLatin1String("O")) { placemark->setZoomLevel( 2 ); } else if (placemarkRole == QLatin1String("K")) { placemark->setZoomLevel( 0 ); } } else { qWarning() << Q_FUNC_INFO << "Unknown feature" << (*i)->nodeType() << ". Skipping."; } } } int FileLoaderPrivate::cityPopIdx( qint64 population ) { int popidx = 3; if ( population < 2500 ) popidx=10; else if ( population < 5000) popidx=9; else if ( population < 25000) popidx=8; else if ( population < 75000) popidx=7; else if ( population < 250000) popidx=6; else if ( population < 750000) popidx=5; else if ( population < 2500000) popidx=4; return popidx; } int FileLoaderPrivate::spacePopIdx( qint64 population ) { int popidx = 1; if ( population < 1000 ) popidx=10; else if ( population < 2000) popidx=9; else if ( population < 8000) popidx=8; else if ( population < 20000) popidx=7; else if ( population < 60000) popidx=6; else if ( population < 100000) popidx=5; else if ( population < 200000 ) popidx=4; else if ( population < 400000 ) popidx=2; else if ( population < 600000 ) popidx=1; return popidx; } int FileLoaderPrivate::areaPopIdx( qreal area ) { int popidx = 1; if ( area < 200000 ) popidx=5; else if ( area < 1000000 ) popidx=4; else if ( area < 2500000 ) popidx=3; else if ( area < 5000000 ) popidx=2; return popidx; } #include "moc_FileLoader.cpp" } // namespace Marble diff --git a/src/lib/marble/FlyToEditWidget.cpp b/src/lib/marble/FlyToEditWidget.cpp index 5dd3dd88f..bb5e817a8 100644 --- a/src/lib/marble/FlyToEditWidget.cpp +++ b/src/lib/marble/FlyToEditWidget.cpp @@ -1,157 +1,155 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2013 Mihail Ivchenko // Copyright 2014 Sanjiban Bairagya // Copyright 2014 Illya Kovalevskyy // #include #include #include #include #include #include "FlyToEditWidget.h" #include "MarbleWidget.h" #include "geodata/data/GeoDataFlyTo.h" #include "GeoDataLookAt.h" -#include "GeoDataTypes.h" #include "GeoDataCamera.h" #include "MarblePlacemarkModel.h" namespace Marble { FlyToEditWidget::FlyToEditWidget( const QModelIndex &index, MarbleWidget* widget, QWidget *parent ) : QWidget( parent ), m_widget( widget ), m_index( index ), m_button( new QToolButton ) { QHBoxLayout *layout = new QHBoxLayout; layout->setSpacing( 5 ); QLabel* iconLabel = new QLabel; iconLabel->setPixmap(QPixmap(QStringLiteral(":/marble/flag.png"))); layout->addWidget( iconLabel ); QHBoxLayout *pairLayout = new QHBoxLayout; pairLayout->setSpacing( 10 ); QHBoxLayout *durationLayout = new QHBoxLayout; durationLayout->setSpacing( 5 ); QLabel *durationLabel = new QLabel; durationLabel->setText( tr("Duration:") ); durationLayout->addWidget( durationLabel ); m_durationSpin = new QDoubleSpinBox; durationLayout->addWidget( m_durationSpin ); m_durationSpin->setValue( flyToElement()->duration() ); m_durationSpin->setSuffix( tr(" s", "seconds") ); QHBoxLayout *modeLayout = new QHBoxLayout; modeLayout->addSpacing( 5 ); QLabel *modeLabel = new QLabel; modeLabel->setText( tr("Mode:") ); modeLayout->addWidget( modeLabel ); m_modeCombo = new QComboBox; modeLayout->addWidget( m_modeCombo ); m_modeCombo->addItem( tr("Smooth") ); m_modeCombo->addItem( tr("Bounce") ); if( flyToElement()->flyToMode() == GeoDataFlyTo::Smooth ){ m_modeCombo->setCurrentIndex( 0 ); } else if( flyToElement()->flyToMode() == GeoDataFlyTo::Bounce ){ m_modeCombo->setCurrentIndex( 1 ); } else { m_modeCombo->setCurrentIndex( -1 ); } pairLayout->addLayout( durationLayout ); pairLayout->addLayout( modeLayout ); layout->addLayout( pairLayout ); QToolButton* flyToPinCenter = new QToolButton; flyToPinCenter->setIcon(QIcon(QStringLiteral(":/marble/places.png"))); flyToPinCenter->setToolTip(tr("Current map center")); connect(flyToPinCenter, SIGNAL(clicked()), this, SLOT(updateCoordinates())); layout->addWidget(flyToPinCenter); m_button->setIcon(QIcon(QStringLiteral(":/marble/document-save.png"))); connect(m_button, SIGNAL(clicked()), this, SLOT(save())); layout->addWidget( m_button ); setLayout( layout ); } bool FlyToEditWidget::editable() const { return m_button->isEnabled(); } void FlyToEditWidget::setEditable( bool editable ) { m_button->setEnabled( editable ); } void FlyToEditWidget::setFirstFlyTo(const QPersistentModelIndex &index) { if( m_index.internalPointer() == index.internalPointer() ) { m_durationSpin->setValue(0); } } void FlyToEditWidget::updateCoordinates() { m_coord = m_widget->focusPoint(); m_coord.setAltitude( m_widget->lookAt().range() ); } void FlyToEditWidget::save() { if (flyToElement()->view() != 0 && m_coord != GeoDataCoordinates()) { GeoDataCoordinates coords = m_coord; - if ( flyToElement()->view()->nodeType() == GeoDataTypes::GeoDataCameraType ) { - GeoDataCamera* camera = dynamic_cast( flyToElement()->view() ); + if (auto camera = geodata_cast(flyToElement()->view())) { camera->setCoordinates( coords ); - } else if ( flyToElement()->view()->nodeType() == GeoDataTypes::GeoDataLookAtType ) { - GeoDataLookAt* lookAt = dynamic_cast( flyToElement()->view() ); + } else if (auto lookAt = geodata_cast(flyToElement()->view())) { lookAt->setCoordinates( coords ); } else{ - GeoDataLookAt* lookAt = new GeoDataLookAt; + lookAt = new GeoDataLookAt; lookAt->setCoordinates( coords ); flyToElement()->setView( lookAt ); } } flyToElement()->setDuration(m_durationSpin->value()); if (m_modeCombo->currentIndex() == 0) { flyToElement()->setFlyToMode( GeoDataFlyTo::Smooth ); } else if (m_modeCombo->currentIndex() == 1) { flyToElement()->setFlyToMode( GeoDataFlyTo::Bounce ); } emit editingDone(m_index); } GeoDataFlyTo* FlyToEditWidget::flyToElement() { GeoDataObject *object = qvariant_cast(m_index.data( MarblePlacemarkModel::ObjectPointerRole ) ); Q_ASSERT( object ); - Q_ASSERT( object->nodeType() == GeoDataTypes::GeoDataFlyToType ); - return static_cast( object ); + auto flyTo = geodata_cast(object); + Q_ASSERT(flyTo); + return flyTo; } } // namespace Marble #include "moc_FlyToEditWidget.cpp" diff --git a/src/lib/marble/GeoDataTreeModel.cpp b/src/lib/marble/GeoDataTreeModel.cpp index 662a4b7ed..c30c623c6 100644 --- a/src/lib/marble/GeoDataTreeModel.cpp +++ b/src/lib/marble/GeoDataTreeModel.cpp @@ -1,946 +1,917 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2010 Thibaut Gridel // Copyright 2013 Levente Kurusa // // Own #include "GeoDataTreeModel.h" // Qt #include #include #include #include // Marble #include "GeoDataObject.h" #include "GeoDataDocument.h" #include "GeoDataContainer.h" #include "GeoDataExtendedData.h" #include "GeoDataFolder.h" #include "GeoDataPlacemark.h" +#include "GeoDataPoint.h" +#include "GeoDataPolygon.h" +#include "GeoDataLinearRing.h" #include "GeoDataLookAt.h" #include "GeoDataMultiGeometry.h" #include "GeoDataPlaylist.h" #include "GeoDataTour.h" #include "GeoDataWait.h" #include "GeoDataFlyTo.h" #include "GeoDataCamera.h" #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include "GeoDataListStyle.h" -#include "GeoDataTypes.h" #include "FileManager.h" #include "MarbleDebug.h" #include "MarblePlacemarkModel.h" using namespace Marble; class Q_DECL_HIDDEN GeoDataTreeModel::Private { public: Private( QAbstractItemModel* model ); ~Private(); static void checkParenting( GeoDataObject *object ); GeoDataDocument* m_rootDocument; bool m_ownsRootDocument; QItemSelectionModel m_selectionModel; QHash m_roleNames; }; GeoDataTreeModel::Private::Private( QAbstractItemModel *model ) : m_rootDocument( new GeoDataDocument ), m_ownsRootDocument( true ), m_selectionModel( model ) { m_roleNames[MarblePlacemarkModel::DescriptionRole] = "description"; m_roleNames[MarblePlacemarkModel::IconPathRole] = "iconPath"; m_roleNames[MarblePlacemarkModel::PopularityIndexRole] = "zoomLevel"; m_roleNames[MarblePlacemarkModel::VisualCategoryRole] = "visualCategory"; m_roleNames[MarblePlacemarkModel::AreaRole] = "area"; m_roleNames[MarblePlacemarkModel::PopulationRole] = "population"; m_roleNames[MarblePlacemarkModel::CountryCodeRole] = "countryCode"; m_roleNames[MarblePlacemarkModel::StateRole] = "state"; m_roleNames[MarblePlacemarkModel::PopularityRole] = "popularity"; m_roleNames[MarblePlacemarkModel::GeoTypeRole] = "role"; m_roleNames[MarblePlacemarkModel::CoordinateRole] = "coordinate"; m_roleNames[MarblePlacemarkModel::StyleRole] = "style"; m_roleNames[MarblePlacemarkModel::GmtRole] = "gmt"; m_roleNames[MarblePlacemarkModel::DstRole] = "dst"; m_roleNames[MarblePlacemarkModel::GeometryRole] = "geometry"; m_roleNames[MarblePlacemarkModel::ObjectPointerRole] = "objectPointer"; m_roleNames[MarblePlacemarkModel::LongitudeRole] = "longitude"; m_roleNames[MarblePlacemarkModel::LatitudeRole] = "latitude"; } GeoDataTreeModel::Private::~Private() { if ( m_ownsRootDocument ) { delete m_rootDocument; } } void GeoDataTreeModel::Private::checkParenting( GeoDataObject *object ) { if (const auto container = dynamic_cast(object)) { for( GeoDataFeature *child: container->featureList() ) { if ( child->parent() != container ) { qWarning() << "Parenting mismatch for " << child->name(); Q_ASSERT( 0 ); } } } } GeoDataTreeModel::GeoDataTreeModel( QObject *parent ) : QAbstractItemModel( parent ), d( new Private( this ) ) { auto const roleNames = QAbstractItemModel::roleNames(); for(auto iter = roleNames.constBegin(); iter != roleNames.constEnd(); ++iter) { d->m_roleNames[iter.key()] = iter.value(); } } GeoDataTreeModel::~GeoDataTreeModel() { delete d; } bool GeoDataTreeModel::hasChildren( const QModelIndex &parent ) const { const GeoDataObject *parentItem; if ( parent.column() > 0 ) { return false; } if ( !parent.isValid() ) { parentItem = d->m_rootDocument; } else { parentItem = static_cast(parent.internalPointer()); } if ( !parentItem ) { return false; } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - const GeoDataPlacemark *placemark = static_cast(parentItem); + if (const auto placemark = geodata_cast(parentItem)) { return dynamic_cast( placemark->geometry() ); } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataFolderType - || parentItem->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - const GeoDataContainer *container = static_cast(parentItem); - return container->size(); + if (const auto folder = geodata_cast(parentItem)) { + return folder->size(); + } + + if (const auto document = geodata_cast(parentItem)) { + return document->size(); } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) { - const GeoDataMultiGeometry *geometry = static_cast(parentItem); + if (const auto geometry = geodata_cast(parentItem)) { return geometry->size(); } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataTourType ) { - const GeoDataTour *tour = static_cast(parentItem); + if (const auto tour = geodata_cast(parentItem)) { return tour->playlist(); } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - const GeoDataPlaylist *playlist = static_cast(parentItem); + if (const auto playlist = geodata_cast(parentItem)) { return playlist->size(); } return false; } int GeoDataTreeModel::rowCount( const QModelIndex &parent ) const { // mDebug() << "rowCount"; const GeoDataObject *parentItem; if ( parent.column() > 0 ) { // mDebug() << "rowCount bad column"; return 0; } if ( !parent.isValid() ) { // mDebug() << "rowCount root parent"; parentItem = d->m_rootDocument; } else { parentItem = static_cast(parent.internalPointer()); } if ( !parentItem ) { // mDebug() << "rowCount bad parent"; return 0; } if (const GeoDataContainer *container = dynamic_cast(parentItem)) { // mDebug() << "rowCount " << type << "(" << parentItem << ") =" << container->size(); return container->size(); // } else { // mDebug() << "rowCount bad container " << container; } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - const GeoDataPlacemark *placemark = static_cast(parentItem); + if (const auto placemark = geodata_cast(parentItem)) { if ( dynamic_cast( placemark->geometry() ) ) { // mDebug() << "rowCount " << type << "(" << parentItem << ") = 1"; return 1; } } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) { - const GeoDataMultiGeometry *geometry = static_cast(parentItem); + if (const auto geometry = geodata_cast(parentItem)) { // mDebug() << "rowCount " << parent << " " << type << " " << geometry->size(); return geometry->size(); // } else { // mDebug() << "rowCount bad geometry " << geometry; } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataTourType ) { - const GeoDataTour *tour = static_cast(parentItem); + if (const auto tour = geodata_cast(parentItem)) { const GeoDataPlaylist *playlist = tour->playlist(); if ( playlist ) { // mDebug() << "rowCount " << parent << " Playlist " << 1; return 1; } } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - const GeoDataPlaylist *playlist = static_cast(parentItem); + if (const auto playlist = geodata_cast(parentItem)) { // mDebug() << "rowCount " << parent << " Playlist " << playlist->size(); return playlist->size(); } // mDebug() << "rowcount end"; return 0;//parentItem->childCount(); } QVariant GeoDataTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if ( role == Qt::DisplayRole && orientation == Qt::Horizontal ) { switch ( section ) { case 0: return tr("Name"); break; case 1: return tr("Type"); break; case 2: return tr("Popularity"); break; case 3: return tr("PopIndex", "Popularity index"); break; } } return QVariant(); } QHash GeoDataTreeModel::roleNames() const { return d->m_roleNames; } QVariant GeoDataTreeModel::data( const QModelIndex &index, int role ) const { // mDebug() << "data"; if ( !index.isValid() ) return QVariant(); GeoDataObject *object = static_cast( index.internalPointer() ); if ( role == Qt::DisplayRole ) { - if ( object->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = static_cast( object ); + if (const auto placemark = geodata_cast(object)) { if ( index.column() == 0 ){ if ( placemark->countryCode().isEmpty() ) { return QVariant( placemark->name() ); } else { return QVariant(placemark->name() + QLatin1String(" (") + placemark->countryCode() + QLatin1Char(')')); } } else if ( index.column() == 1 ){ return QVariant( placemark->nodeType() ); } else if ( index.column() == 2 ){ return QVariant( placemark->popularity() ); } else if ( index.column() == 3 ){ return QVariant( placemark->zoomLevel() ); } } if (const auto feature = dynamic_cast(object)) { if ( index.column() == 0 ){ return QVariant( feature->name() ); } else if ( index.column() == 1 ){ return QVariant( feature->nodeType() ); } } GeoDataGeometry *geometry = dynamic_cast( object ); if ( geometry && index.column() == 1 ){ return QVariant( geometry->nodeType() ); } GeoDataPlaylist *playlist = dynamic_cast( object ); if ( playlist && index.column() == 0 ) { return tr( "Playlist" ); } GeoDataObject *item = dynamic_cast( object ); if ( item && index.column() == 1 ){ return QVariant( item->nodeType() ); } } else if ( role == Qt::CheckStateRole && index.column() == 0 ) { - if ( object->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *feature = static_cast( object ); - if ( feature->parent()->nodeType() == GeoDataTypes::GeoDataFolderType ) { - GeoDataFolder *folder = static_cast( feature->parent() ); + if (const auto feature = geodata_cast(object)) { + if (const auto folder = geodata_cast(feature->parent())) { if ( folder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder || folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckOffOnly) { if ( feature->isVisible() ) { return QVariant ( Qt::Checked ); } else { return QVariant ( Qt::Unchecked ); } } } if (feature->isGloballyVisible()) { return QVariant(Qt::Checked); } if (feature->isVisible()) { return QVariant(Qt::PartiallyChecked); } return QVariant(Qt::Unchecked); } else if (auto feature = dynamic_cast(object)) { - if ( object->nodeType() == GeoDataTypes::GeoDataFolderType ) { - GeoDataFolder *folder = static_cast( object ); + if (auto folder = geodata_cast(object)) { if ( folder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder) { bool anyVisible = false; QVector::Iterator i = folder->begin(); for (; i < folder->end(); ++i) { if ((*i)->isVisible()) { anyVisible = true; break; } } if (anyVisible) { return QVariant( Qt::PartiallyChecked ); } else { return QVariant( Qt::Unchecked ); } } else if ( folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckOffOnly) { QVector::Iterator i = folder->begin(); bool anyVisible = false; bool allVisible = true; for (; i < folder->end(); ++i) { if ((*i)->isVisible()) { anyVisible = true; } else { allVisible = false; } } if (allVisible) { return QVariant( Qt::Checked ); } else if (anyVisible) { return QVariant( Qt::PartiallyChecked ); } else { return QVariant( Qt::Unchecked ); } } } if ( feature->isGloballyVisible() ) { return QVariant( Qt::Checked ); } else if ( feature->isVisible() ) { return QVariant( Qt::PartiallyChecked ); } else { return QVariant( Qt::Unchecked ); } } } else if ( role == Qt::DecorationRole && index.column() == 0 ) { if (const auto feature = dynamic_cast(object)) { if (feature->style()->iconStyle().icon().isNull()) { return QImage(); } return QVariant(feature->style()->iconStyle().icon().scaled( QSize(16,16), Qt::KeepAspectRatio, Qt::SmoothTransformation )); } } else if ( role == Qt::ToolTipRole && index.column() == 0 ) { if (const auto feature = dynamic_cast(object)) { return QVariant( feature->description() ); } } else if ( role == MarblePlacemarkModel::ObjectPointerRole ) { return qVariantFromValue( object ); } else if ( role == MarblePlacemarkModel::PopularityIndexRole ) { - if ( object->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = static_cast( object ); + if (const auto placemark = geodata_cast(object)) { return QVariant( placemark->zoomLevel() ); } } else if ( role == MarblePlacemarkModel::PopularityRole ) { - if ( object->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = static_cast( object ); + if (const auto placemark = geodata_cast(object)) { return QVariant( placemark->popularity() ); } } else if ( role == MarblePlacemarkModel::CoordinateRole ) { - if ( object->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = static_cast( object ); + if (const auto placemark = geodata_cast(object)) { return qVariantFromValue( placemark->coordinate() ); - } else if ( object->nodeType() == GeoDataTypes::GeoDataFlyToType ) { - GeoDataFlyTo *flyTo = static_cast( object ); - if ( flyTo->view() && flyTo->view()->nodeType() == GeoDataTypes::GeoDataCameraType ) { - GeoDataCamera *camera = static_cast( flyTo->view() ); + } else if (const auto flyTo = geodata_cast(object)) { + if (const auto camera = geodata_cast(flyTo->view())) { return QVariant::fromValue( camera->coordinates() ); - } else if ( flyTo->view() && flyTo->view()->nodeType() == GeoDataTypes::GeoDataLookAtType ) { - GeoDataLookAt *lookAt = static_cast( flyTo->view() ); + } else if (const auto lookAt = (flyTo->view() ? geodata_cast(flyTo->view()) : 0)) { return QVariant::fromValue( lookAt->coordinates() ); } } } else if ( role == Qt::BackgroundRole ) { - if ( object->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = static_cast( object ); + if (const auto placemark = geodata_cast(object)) { if (const GeoDataContainer *container = dynamic_cast(placemark->parent())) { return container->customStyle() ? QVariant( QBrush( container->customStyle()->listStyle().backgroundColor() )) : QVariant(); } } } else if (role == MarblePlacemarkModel::IconPathRole) { - if (object->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - GeoDataPlacemark *placemark = static_cast(object); + if (const auto placemark = geodata_cast(object)) { return placemark->style()->iconStyle().iconPath(); } } return QVariant(); } QModelIndex GeoDataTreeModel::index( int row, int column, const QModelIndex &parent ) const { // mDebug() << "index"; if ( !hasIndex( row, column, parent ) ) { // mDebug() << "index bad index"; return QModelIndex(); } GeoDataObject *parentItem; if ( !parent.isValid() ) parentItem = d->m_rootDocument; else parentItem = static_cast( parent.internalPointer() ); if ( !parentItem ) { // mDebug() << "index bad parent"; return QModelIndex(); } GeoDataObject *childItem = 0; if (auto container = dynamic_cast(parentItem)) { childItem = container->child( row ); return createIndex( row, column, childItem ); } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = static_cast( parentItem ); + if (const auto placemark = geodata_cast(parentItem)) { childItem = placemark->geometry(); if ( dynamic_cast( childItem ) ) { return createIndex( row, column, childItem ); } } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) { - GeoDataMultiGeometry *geometry = static_cast( parentItem ); + if (const auto geometry = geodata_cast(parentItem)) { childItem = geometry->child( row ); return createIndex( row, column, childItem ); } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataTourType ) { - GeoDataTour *tour = static_cast( parentItem ); + if (const auto tour = geodata_cast(parentItem)) { childItem = tour->playlist(); return createIndex( row, column, childItem ); } - if ( parentItem->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( parentItem ); + if (const auto playlist = geodata_cast(parentItem)) { childItem = playlist->primitive( row ); return createIndex(row, column, childItem); } return QModelIndex(); } QModelIndex GeoDataTreeModel::parent( const QModelIndex &index ) const { // mDebug() << "parent"; if ( !index.isValid() ) { // mDebug() << "parent bad index"; return QModelIndex(); } GeoDataObject *childObject = static_cast( index.internalPointer() ); if ( childObject ) { /// parentObject can be a container, placemark, multigeometry or playlist GeoDataObject *parentObject = childObject->parent(); if ( parentObject == d->m_rootDocument ) { return QModelIndex(); } GeoDataObject *greatParentObject = parentObject->parent(); // Avoid crashing when there is no grandparent if ( greatParentObject == 0 ) { return QModelIndex(); } // greatParent can be a container if (auto greatparentContainer = dynamic_cast(greatParentObject)) { GeoDataFeature *parentFeature = static_cast( parentObject ); // mDebug() << "parent " << childObject->nodeType() << "(" << childObject << ") = " // << parentObject->nodeType() << "[" << greatparentContainer->childPosition( parentFeature ) << "](" << parentObject << ")"; return createIndex( greatparentContainer->childPosition( parentFeature ), 0, parentObject ); } // greatParent can be a placemark - if ( greatParentObject->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { + if (geodata_cast(greatParentObject)) { // GeoDataPlacemark *greatparentPlacemark = static_cast( greatParentObject ); // mDebug() << "parent " << childObject->nodeType() << "(" << childObject << ") = " // << parentObject->nodeType() << "[0](" << parentObject << ")"; return createIndex( 0, 0, parentObject ); } // greatParent can be a multigeometry - if ( greatParentObject->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) { - GeoDataMultiGeometry *greatparentMultiGeo = static_cast( greatParentObject ); + if (GeoDataMultiGeometry *greatparentMultiGeo = geodata_cast(greatParentObject)) { GeoDataGeometry *parentGeometry = static_cast( parentObject ); // mDebug() << "parent " << childObject->nodeType() << "(" << childObject << ") = " // << parentObject->nodeType() << "[" << greatParentItem->childPosition( parentGeometry ) << "](" << parentObject << ")"; return createIndex( greatparentMultiGeo->childPosition( parentGeometry ), 0, parentObject ); } - if ( greatParentObject->nodeType() == GeoDataTypes::GeoDataTourType ) { - GeoDataTour *tour = static_cast( greatParentObject ); + if (GeoDataTour *tour = geodata_cast(greatParentObject)) { return createIndex( 0, 0, tour->playlist() ); } } // mDebug() << "parent unknown index"; return QModelIndex(); } int GeoDataTreeModel::columnCount( const QModelIndex & ) const { return 4; } bool GeoDataTreeModel::setData ( const QModelIndex & index, const QVariant & value, int role ) { if ( !index.isValid() ) return false; GeoDataObject *object = static_cast( index.internalPointer() ); if ( role == Qt::CheckStateRole ) { if (auto feature = dynamic_cast(object)) { bool bValue = value.toBool(); - if (feature->parent()->nodeType() == GeoDataTypes::GeoDataFolderType) { - GeoDataFolder *pfolder = static_cast(feature->parent()); + if (auto pfolder = geodata_cast(feature->parent())) { if ( pfolder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder) { if ( bValue ) { QVector< GeoDataFeature * >::Iterator i = pfolder->begin(); for(; i < pfolder->end(); ++i) { (*i)->setVisible( false ); } } } } - if ( feature->nodeType() == GeoDataTypes::GeoDataFolderType) { - GeoDataFolder *folder = static_cast( object ); + if (auto folder = geodata_cast(object)) { if ( bValue ) { } else { if ( folder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder || folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckOffOnly ) { QVector< GeoDataFeature * >::Iterator i = folder->begin(); for(; i < folder->end(); ++i) { (*i)->setVisible( false ); } folder->setVisible( false ); } } } feature->setVisible( bValue ); mDebug() << "setData " << feature->name(); updateFeature( feature ); return true; } } else if ( role == Qt::EditRole ) { if (auto feature = dynamic_cast(object)) { feature->setName( value.toString() ); mDebug() << "setData " << feature->name() << " " << value.toString(); updateFeature( feature ); return true; } } return false; } Qt::ItemFlags GeoDataTreeModel::flags ( const QModelIndex & index ) const { if ( !index.isValid() ) return Qt::NoItemFlags; const GeoDataObject *object = static_cast(index.internalPointer()); - if ( object->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - const GeoDataFeature *feature = static_cast(object); + if (const auto feature = geodata_cast(object)) { const GeoDataObject *parent = feature->parent(); - if ( parent->nodeType() == GeoDataTypes::GeoDataFolderType ) { - const GeoDataFolder *parentfolder = static_cast(parent); + if (const auto parentfolder = geodata_cast(parent)) { if ( parentfolder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder ) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable; } else if ( parentfolder->style()->listStyle().listItemType() == GeoDataListStyle::CheckHideChildren ) { return 0; } } } - if ( object->nodeType() == GeoDataTypes::GeoDataFolderType ) { - const GeoDataFolder *folder = static_cast(object); + + if (const auto folder = geodata_cast(object)) { if ( folder->style()->listStyle().listItemType() == GeoDataListStyle::RadioFolder) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable; } else if ( folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckOffOnly ) { QVector::ConstIterator i = folder->constBegin(); bool allVisible = true; for (; i < folder->constEnd(); ++i) { if( ! (*i)->isVisible() ) { allVisible = false; break; } } if ( allVisible ) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable; } else { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; } } else if ( folder->style()->listStyle().listItemType() == GeoDataListStyle::CheckHideChildren) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable; } } - if (object->nodeType() == GeoDataTypes::GeoDataTourType) { + if (geodata_cast(object)) { return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; } if (dynamic_cast(object)) { const GeoDataObject *parent = object; - while( parent->nodeType() != GeoDataTypes::GeoDataDocumentType ) { + while (!geodata_cast(parent)) { parent = parent->parent(); } const GeoDataDocument *document = static_cast(parent); if( document->documentRole() == UserDocument ) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable;; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; } - if ( object->nodeType() == GeoDataTypes::GeoDataWaitType - || object->nodeType() == GeoDataTypes::GeoDataFlyToType - || object->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { + if (geodata_cast(object) + || geodata_cast(object) + || geodata_cast(object)) { return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QModelIndex GeoDataTreeModel::index( GeoDataObject *object ) const { if ( object == 0 ) return QModelIndex(); //It first runs bottom-top, storing every ancestor of the object, and //then goes top-down retrieving the QModelIndex of every ancestor until reaching the //index of the requested object. //The TreeModel contains: Documents, Folders, Placemarks, MultiGeometries //and Geometries that are children of MultiGeometries //You can not call this function with an element that does not belong to the tree - Q_ASSERT( ( object->nodeType() == GeoDataTypes::GeoDataFolderType ) - || ( object->nodeType() == GeoDataTypes::GeoDataDocumentType ) - || ( object->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) - || ( object->nodeType() == GeoDataTypes::GeoDataTourType ) - || ( ( object->nodeType() == GeoDataTypes::GeoDataPlaylistType ) - && ( object->parent()->nodeType() == GeoDataTypes::GeoDataTourType ) ) - || ( ( object->nodeType() == GeoDataTypes::GeoDataWaitType ) - && ( object->parent()->nodeType() == GeoDataTypes::GeoDataPlaylistType ) ) - || ( ( object->nodeType() == GeoDataTypes::GeoDataFlyToType ) - && ( object->parent()->nodeType() == GeoDataTypes::GeoDataPlaylistType ) ) - || ( ( object->nodeType() == GeoDataTypes::GeoDataLineStringType ) - && ( object->parent()->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) ) - || ( ( object->nodeType() == GeoDataTypes::GeoDataLinearRingType ) - && ( object->parent()->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) ) - || ( ( object->nodeType() == GeoDataTypes::GeoDataPointType ) - && ( object->parent()->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) ) - || ( ( object->nodeType() == GeoDataTypes::GeoDataPolygonType ) - && ( object->parent()->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) ) - || ( object->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) ); + Q_ASSERT(geodata_cast(object) + || geodata_cast(object) + || geodata_cast(object) + || geodata_cast(object) + || ( geodata_cast(object) + && geodata_cast(object->parent())) + || (geodata_cast(object) + && geodata_cast(object->parent())) + || ( geodata_cast(object) + && geodata_cast(object->parent())) + || (geodata_cast(object) + && geodata_cast(object->parent())) + || (geodata_cast(object) + && geodata_cast(object->parent())) + || (geodata_cast(object) + && geodata_cast(object->parent())) + || (geodata_cast(object) + && geodata_cast(object->parent())) + || geodata_cast(object)); QList< GeoDataObject* > ancestors; GeoDataObject *itup = object; //Iterator to reach the top of the GeoDataDocument (bottom-up) while ( itup && ( itup != d->m_rootDocument ) ) {//We reach up to the rootDocument ancestors.append( itup ); itup = itup->parent() ; } QModelIndex itdown; if ( !ancestors.isEmpty() ) { itdown = index( d->m_rootDocument->childPosition( static_cast( ancestors.last() ) ),0,QModelIndex());//Iterator to go top down while ( ( ancestors.size() > 1 ) ) { GeoDataObject *parent = static_cast( ancestors.last() ); if (const auto container = dynamic_cast(parent)) { ancestors.removeLast(); itdown = index(container->childPosition(static_cast(ancestors.last())), 0, itdown); - } else if ( ( parent->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) ) { + } else if (geodata_cast(parent)) { //The only child of the model is a Geometry or MultiGeometry object //If it is a geometry object, we should be on the bottom of the list ancestors.removeLast(); - if( ancestors.last()->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) + if (geodata_cast(ancestors.last())) itdown = index( 0 , 0, itdown ); else itdown = QModelIndex(); - } else if ( ( parent->nodeType() == GeoDataTypes::GeoDataMultiGeometryType ) ) { + } else if (auto multiGeometry = geodata_cast(parent)) { //The child is one of the geometry children of MultiGeometry ancestors.removeLast(); - itdown = index( static_cast(parent)->childPosition( static_cast(ancestors.last()) ) , 0, itdown ); - } else if ( ( parent->nodeType() == GeoDataTypes::GeoDataTourType ) ) { + itdown = index(multiGeometry->childPosition( static_cast(ancestors.last()) ) , 0, itdown ); + } else if (geodata_cast(parent)) { ancestors.removeLast(); itdown = index( 0, 0, itdown ); - } else if ( ( parent->nodeType() == GeoDataTypes::GeoDataPlaylistType ) ) { - GeoDataPlaylist *playlist = static_cast( parent ); + } else if (auto playlist = geodata_cast(parent)) { for ( int i=0; i< playlist->size(); i++ ) { if ( playlist->primitive(i) == ancestors.last() ) { ancestors.removeLast(); itdown = index( i, 0, itdown ); break; } } } else { //If the element is not found on the tree, it will be added under m_rootDocument itdown = QModelIndex(); break; } } } return itdown; } QItemSelectionModel *GeoDataTreeModel::selectionModel() { return &d->m_selectionModel; } int GeoDataTreeModel::addFeature( GeoDataContainer *parent, GeoDataFeature *feature, int row ) { if ( parent && feature ) { QModelIndex modelindex = index( parent ); //index(GeoDataObject*) returns QModelIndex() if parent == m_rootDocument //or if parent is not found on the tree. //We must check that we are in top of the tree (then QModelIndex() is //the right parent to insert the child object) or that we have a valid QModelIndex if( ( parent == d->m_rootDocument ) || modelindex.isValid() ) { if( row < 0 || row > parent->size()) { row = parent->size(); } beginInsertRows( modelindex , row , row ); parent->insert( row, feature ); d->checkParenting( parent ); endInsertRows(); emit added(feature); } else qWarning() << "GeoDataTreeModel::addFeature (parent " << parent << " - feature" << feature << ") : parent not found on the TreeModel"; } else qWarning() << "Null pointer in call to GeoDataTreeModel::addFeature (parent " << parent << " - feature" << feature << ")"; return row; //-1 if it failed, the relative index otherwise. } int GeoDataTreeModel::addDocument( GeoDataDocument *document ) { return addFeature( d->m_rootDocument, document ); } bool GeoDataTreeModel::removeFeature( GeoDataContainer *parent, int row ) { if ( rowsize() ) { beginRemoveRows( index( parent ), row , row ); GeoDataFeature *feature = parent->child( row ); parent->remove( row ); emit removed(feature); endRemoveRows(); return true; } return false; //Tried to remove a row that is not contained in the parent. } int GeoDataTreeModel::removeFeature(GeoDataFeature *feature) { if ( feature && ( feature!=d->m_rootDocument ) ) { if (!feature->parent()) { return -1; } //We check to see we are not removing the //top level element m_rootDocument GeoDataObject *parent = static_cast< GeoDataObject* >( feature->parent() ); if (dynamic_cast(parent)) { int row = static_cast< GeoDataContainer* >( feature->parent() )->childPosition( feature ); if ( row != -1 ) { bool removed = removeFeature( static_cast< GeoDataContainer* >( feature->parent() ) , row ); if( removed ) { return row; } } //The feature is not contained in the parent it points to } } return -1; //We can not remove the rootDocument } void GeoDataTreeModel::updateFeature( GeoDataFeature *feature ) { GeoDataContainer *container = static_cast( feature->parent() ); int index = removeFeature( feature ); Q_ASSERT( index != -1 ); addFeature( container, feature, index ); } void GeoDataTreeModel::removeDocument( int index ) { removeFeature( d->m_rootDocument, index ); } void GeoDataTreeModel::removeDocument( GeoDataDocument *document ) { removeFeature( document ); } void GeoDataTreeModel::setRootDocument( GeoDataDocument* document ) { beginResetModel(); if ( d->m_ownsRootDocument ) { delete d->m_rootDocument; } d->m_ownsRootDocument = ( document == 0 ); d->m_rootDocument = document ? document : new GeoDataDocument; endResetModel(); } GeoDataDocument * GeoDataTreeModel::rootDocument() { return d->m_rootDocument; } int GeoDataTreeModel::addTourPrimitive( const QModelIndex &parent, GeoDataTourPrimitive *primitive, int row ) { GeoDataObject *parentObject = static_cast( parent.internalPointer() ); - if( parent.isValid() && parentObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( parentObject ); + if (auto playlist = geodata_cast(parentObject)) { if( row == -1 ) { row = playlist->size(); } beginInsertRows( parent, row, row ); playlist->insertPrimitive( row, primitive ); endInsertRows(); return row; } return -1; } bool GeoDataTreeModel::removeTourPrimitive( const QModelIndex &parent , int index) { GeoDataObject *parentObject = static_cast( parent.internalPointer() ); - if( parent.isValid() && parentObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( parentObject ); + if (auto playlist = (parent.isValid() ? geodata_cast(parentObject) : 0)) { if( playlist->size() > index ) { beginRemoveRows( parent, index, index ); playlist->removePrimitiveAt( index ); endRemoveRows(); return true; } } return false; } bool GeoDataTreeModel::swapTourPrimitives( const QModelIndex &parent, int indexA, int indexB ) { GeoDataObject *parentObject = static_cast( parent.internalPointer() ); - if( parent.isValid() && parentObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( parentObject ); + if (auto playlist = (parent.isValid() ? geodata_cast(parentObject) : 0)) { if( indexA > indexB ) { qSwap(indexA, indexB); } if ( indexB - indexA == 1 ) { beginMoveRows( parent, indexA, indexA, parent, indexB+1 ); } else { beginMoveRows( parent, indexA, indexA, parent, indexB ); beginMoveRows( parent, indexB, indexB, parent, indexA ); } playlist->swapPrimitives( indexA, indexB ); if( indexB - indexA != 1 ) { endMoveRows(); } endMoveRows(); return true; } return false; } #include "moc_GeoDataTreeModel.cpp" diff --git a/src/lib/marble/GeoGraphicsScene.cpp b/src/lib/marble/GeoGraphicsScene.cpp index e38d7b69d..9ad0c84a2 100644 --- a/src/lib/marble/GeoGraphicsScene.cpp +++ b/src/lib/marble/GeoGraphicsScene.cpp @@ -1,281 +1,279 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2011 Konstantin Oblaukhov // #include "GeoGraphicsScene.h" #include "GeoDataFeature.h" #include "GeoDataLatLonAltBox.h" #include "GeoDataStyle.h" #include "GeoDataStyleMap.h" #include "GeoDataPlacemark.h" #include "GeoDataDocument.h" -#include "GeoDataTypes.h" #include "GeoGraphicsItem.h" #include "TileId.h" #include "TileCoordsPyramid.h" #include "MarbleDebug.h" #include #include namespace Marble { class GeoGraphicsScenePrivate { public: GeoGraphicsScene *q; explicit GeoGraphicsScenePrivate(GeoGraphicsScene *parent) : q(parent) { } ~GeoGraphicsScenePrivate() { q->clear(); } typedef QHash FeatureItemMap; QHash m_tiledItems; QMultiHash m_features; // multi hash because multi track and multi geometry insert multiple items // Stores the items which have been clicked; QList m_selectedItems; GeoDataStyle::Ptr highlightStyle(const GeoDataDocument *document, const GeoDataStyleMap &styleMap); void selectItem( GeoGraphicsItem *item ); void applyHighlightStyle(GeoGraphicsItem *item, const GeoDataStyle::Ptr &style ); }; GeoDataStyle::Ptr GeoGraphicsScenePrivate::highlightStyle( const GeoDataDocument *document, const GeoDataStyleMap &styleMap ) { // @todo Consider QUrl parsing when external styles are suppported QString highlightStyleId = styleMap.value(QStringLiteral("highlight")); highlightStyleId.remove(QLatin1Char('#')); if ( !highlightStyleId.isEmpty() ) { GeoDataStyle::Ptr highlightStyle(new GeoDataStyle( *document->style(highlightStyleId) )); return highlightStyle; } else { return GeoDataStyle::Ptr(); } } void GeoGraphicsScenePrivate::selectItem( GeoGraphicsItem* item ) { m_selectedItems.append( item ); } void GeoGraphicsScenePrivate::applyHighlightStyle(GeoGraphicsItem* item, const GeoDataStyle::Ptr &highlightStyle ) { item->setHighlightStyle( highlightStyle ); item->setHighlighted( true ); } GeoGraphicsScene::GeoGraphicsScene( QObject* parent ): QObject( parent ), d( new GeoGraphicsScenePrivate(this) ) { } GeoGraphicsScene::~GeoGraphicsScene() { delete d; } QList< GeoGraphicsItem* > GeoGraphicsScene::items( const GeoDataLatLonBox &box, int zoomLevel ) const { if ( box.west() > box.east() ) { // Handle boxes crossing the IDL by splitting it into two separate boxes GeoDataLatLonBox left; left.setWest( -M_PI ); left.setEast( box.east() ); left.setNorth( box.north() ); left.setSouth( box.south() ); GeoDataLatLonBox right; right.setWest( box.west() ); right.setEast( M_PI ); right.setNorth( box.north() ); right.setSouth( box.south() ); return items(left, zoomLevel) + items(right, zoomLevel); } QList< GeoGraphicsItem* > result; QRect rect; qreal north, south, east, west; box.boundaries( north, south, east, west ); TileId key; key = TileId::fromCoordinates( GeoDataCoordinates(west, north, 0), zoomLevel ); rect.setLeft( key.x() ); rect.setTop( key.y() ); key = TileId::fromCoordinates( GeoDataCoordinates(east, south, 0), zoomLevel ); rect.setRight( key.x() ); rect.setBottom( key.y() ); TileCoordsPyramid pyramid( 0, zoomLevel ); pyramid.setBottomLevelCoords( rect ); for ( int level = pyramid.topLevel(); level <= pyramid.bottomLevel(); ++level ) { QRect const coords = pyramid.coords( level ); int x1, y1, x2, y2; coords.getCoords( &x1, &y1, &x2, &y2 ); for ( int x = x1; x <= x2; ++x ) { bool const isBorderX = x == x1 || x == x2; for ( int y = y1; y <= y2; ++y ) { bool const isBorder = isBorderX || y == y1 || y == y2; const TileId tileId = TileId( 0, level, x, y ); for(GeoGraphicsItem *object: d->m_tiledItems.value( tileId )) { if (object->minZoomLevel() <= zoomLevel && object->visible()) { if (!isBorder || object->latLonAltBox().intersects(box)) { result.push_back(object); } } } } } } return result; } QList< GeoGraphicsItem* > GeoGraphicsScene::selectedItems() const { return d->m_selectedItems; } void GeoGraphicsScene::resetStyle() { for (auto const & items: d->m_tiledItems) { for (auto item: items) { item->resetStyle(); } } emit repaintNeeded(); } void GeoGraphicsScene::applyHighlight( const QVector< GeoDataPlacemark* > &selectedPlacemarks ) { /** * First set the items, which were selected previously, to * use normal style */ for ( GeoGraphicsItem *item: d->m_selectedItems ) { item->setHighlighted( false ); } // Also clear the list to store the new selected items d->m_selectedItems.clear(); /** * Process the placemark. which were under mouse * while clicking, and update corresponding graphics * items to use highlight style */ for( const GeoDataPlacemark *placemark: selectedPlacemarks ) { for (auto tileIter = d->m_features.find(placemark); tileIter != d->m_features.end() && tileIter.key() == placemark; ++tileIter) { auto const & clickedItems = d->m_tiledItems[*tileIter]; auto iter = clickedItems.find(placemark); if (iter != clickedItems.end()) { const GeoDataObject *parent = placemark->parent(); if ( parent ) { auto item = *iter; - if ( parent->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - const GeoDataDocument *doc = static_cast(parent); + if (const GeoDataDocument *doc = geodata_cast(parent)) { QString styleUrl = placemark->styleUrl(); styleUrl.remove(QLatin1Char('#')); if ( !styleUrl.isEmpty() ) { GeoDataStyleMap const &styleMap = doc->styleMap( styleUrl ); GeoDataStyle::Ptr style = d->highlightStyle( doc, styleMap ); if ( style ) { d->selectItem( item ); d->applyHighlightStyle( item, style ); } } /** * If a placemark is using an inline style instead of a shared * style ( e.g in case when theme file specifies the colorMap * attribute ) then highlight it if any of the style maps have a * highlight styleId */ else { for ( const GeoDataStyleMap &styleMap: doc->styleMaps() ) { GeoDataStyle::Ptr style = d->highlightStyle( doc, styleMap ); if ( style ) { d->selectItem( item ); d->applyHighlightStyle( item, style ); break; } } } } } } } } emit repaintNeeded(); } void GeoGraphicsScene::removeItem( const GeoDataFeature* feature ) { for (auto tileIter = d->m_features.find(feature), end = d->m_features.end(); tileIter != end && tileIter.key() == feature;) { auto & tileList = d->m_tiledItems[*tileIter]; auto iter = tileList.find(feature); if (iter != tileList.end()) { auto item = iter.value(); tileIter = d->m_features.erase(tileIter); tileList.erase(iter); delete item; } else { ++tileIter; } } } void GeoGraphicsScene::clear() { for(auto const &list: d->m_tiledItems.values()) { qDeleteAll(list.values()); } d->m_tiledItems.clear(); d->m_features.clear(); } void GeoGraphicsScene::addItem( GeoGraphicsItem* item ) { // Select zoom level so that the object fit in single tile int zoomLevel; qreal north, south, east, west; item->latLonAltBox().boundaries( north, south, east, west ); for(zoomLevel = item->minZoomLevel(); zoomLevel >= 0; zoomLevel--) { if( TileId::fromCoordinates( GeoDataCoordinates(west, north, 0), zoomLevel ) == TileId::fromCoordinates( GeoDataCoordinates(east, south, 0), zoomLevel ) ) break; } const TileId key = TileId::fromCoordinates( GeoDataCoordinates(west, north, 0), zoomLevel ); // same as GeoDataCoordinates(east, south, 0), see above auto & tileList = d->m_tiledItems[key]; auto feature = item->feature(); tileList.insert(feature, item); d->m_features.insert(feature, key ); } } #include "moc_GeoGraphicsScene.cpp" diff --git a/src/lib/marble/MarbleModel.cpp b/src/lib/marble/MarbleModel.cpp index 2862c0ffb..70ab328f0 100644 --- a/src/lib/marble/MarbleModel.cpp +++ b/src/lib/marble/MarbleModel.cpp @@ -1,927 +1,923 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2006-2007 Torsten Rahn // Copyright 2007 Inge Wallin // Copyright 2008, 2009, 2010 Jens-Michael Hoffmann // Copyright 2008-2009 Patrick Spendrin // Copyright 2010-2013 Bernhard Beschow // Copyright 2014 Abhinav Gangwar // #include "MarbleModel.h" #include #include #include #include #include #include #include #include "kdescendantsproxymodel.h" #include "MapThemeManager.h" #include "MarbleGlobal.h" #include "MarbleDebug.h" #include "GeoSceneDocument.h" #include "GeoSceneGeodata.h" #include "GeoSceneHead.h" #include "GeoSceneLayer.h" #include "GeoSceneMap.h" #include "GeoScenePalette.h" #include "GeoSceneTileDataset.h" #include "GeoSceneVector.h" #include "GeoDataDocument.h" #include "GeoDataFeature.h" #include "GeoDataPlacemark.h" +#include "GeoDataPoint.h" #include "GeoDataStyle.h" #include "GeoDataStyleMap.h" +#include "GeoDataTrack.h" #include "GeoDataLineStyle.h" #include "GeoDataPolyStyle.h" #include "GeoDataTypes.h" #include "DgmlAuxillaryDictionary.h" #include "MarbleClock.h" #include "FileStoragePolicy.h" #include "FileStorageWatcher.h" #include "PositionTracking.h" #include "HttpDownloadManager.h" #include "MarbleDirs.h" #include "FileManager.h" #include "GeoDataTreeModel.h" #include "PlacemarkPositionProviderPlugin.h" #include "Planet.h" #include "PlanetFactory.h" #include "PluginManager.h" #include "StoragePolicy.h" #include "SunLocator.h" #include "TileCreator.h" #include "TileCreatorDialog.h" #include "TileLoader.h" #include "routing/RoutingManager.h" #include "RouteSimulationPositionProviderPlugin.h" #include "BookmarkManager.h" #include "ElevationModel.h" namespace Marble { class MarbleModelPrivate { public: MarbleModelPrivate() : m_clock(), m_planet(PlanetFactory::construct(QStringLiteral("earth"))), m_sunLocator( &m_clock, &m_planet ), m_pluginManager(), m_homePoint( -9.4, 54.8, 0.0, GeoDataCoordinates::Degree ), // Some point that tackat defined. :-) m_homeZoom( 1050 ), m_mapTheme( 0 ), m_storagePolicy( MarbleDirs::localPath() ), m_downloadManager( &m_storagePolicy ), m_storageWatcher( MarbleDirs::localPath() ), m_treeModel(), m_descendantProxy(), m_placemarkProxyModel(), m_placemarkSelectionModel( 0 ), m_fileManager( &m_treeModel, &m_pluginManager ), m_positionTracking( &m_treeModel ), m_trackedPlacemark( 0 ), m_bookmarkManager( &m_treeModel ), m_routingManager( 0 ), m_legend( 0 ), m_workOffline( false ), m_elevationModel( &m_downloadManager, &m_pluginManager ) { m_descendantProxy.setSourceModel( &m_treeModel ); m_placemarkProxyModel.setFilterFixedString( GeoDataTypes::GeoDataPlacemarkType ); m_placemarkProxyModel.setFilterKeyColumn( 1 ); m_placemarkProxyModel.setSourceModel( &m_descendantProxy ); m_placemarkSelectionModel.setModel(&m_placemarkProxyModel); m_groundOverlayProxyModel.setFilterFixedString( GeoDataTypes::GeoDataGroundOverlayType ); m_groundOverlayProxyModel.setFilterKeyColumn( 1 ); m_groundOverlayProxyModel.setSourceModel( &m_descendantProxy ); } ~MarbleModelPrivate() { delete m_mapTheme; delete m_legend; } /** * @brief When applying a new theme, if the old theme * contains any data whose source file is same * as any of the source file in new theme, don't parse * the source file again. Instead just update the * styling info, based on and * value for that source file in new theme, in * the already parsed data. If the element * in new theme has some value for colorMap attribute * then we go for assignFillColors() which assigns each * placemark an inline style based on colors specified * in colorMap attribute. This avoid extra CPU * load of parsing the data file again. * @see assignFillColors() */ void assignNewStyle(const QString &filePath, const GeoDataStyle::Ptr &style ); /** * @brief Assigns each placemark an inline * style based on the color values specified * by colorMap attribute under element * in theme file. */ void assignFillColors( const QString &filePath ); void addHighlightStyle( GeoDataDocument *doc ); // Misc stuff. MarbleClock m_clock; Planet m_planet; SunLocator m_sunLocator; PluginManager m_pluginManager; // The home position GeoDataCoordinates m_homePoint; int m_homeZoom; // View and paint stuff GeoSceneDocument *m_mapTheme; FileStoragePolicy m_storagePolicy; HttpDownloadManager m_downloadManager; // Cache related FileStorageWatcher m_storageWatcher; // Places on the map GeoDataTreeModel m_treeModel; KDescendantsProxyModel m_descendantProxy; QSortFilterProxyModel m_placemarkProxyModel; QSortFilterProxyModel m_groundOverlayProxyModel; // Selection handling QItemSelectionModel m_placemarkSelectionModel; FileManager m_fileManager; //Gps Stuff PositionTracking m_positionTracking; const GeoDataPlacemark *m_trackedPlacemark; BookmarkManager m_bookmarkManager; RoutingManager *m_routingManager; QTextDocument *m_legend; bool m_workOffline; ElevationModel m_elevationModel; }; MarbleModel::MarbleModel( QObject *parent ) : QObject( parent ), d( new MarbleModelPrivate() ) { // connect the StoragePolicy used by the download manager to the FileStorageWatcher connect( &d->m_storagePolicy, SIGNAL(cleared()), &d->m_storageWatcher, SLOT(resetCurrentSize()) ); connect( &d->m_storagePolicy, SIGNAL(sizeChanged(qint64)), &d->m_storageWatcher, SLOT(addToCurrentSize(qint64)) ); connect( &d->m_fileManager, SIGNAL(fileAdded(QString)), this, SLOT(assignFillColors(QString)) ); d->m_routingManager = new RoutingManager( this, this ); connect(&d->m_clock, SIGNAL(timeChanged()), &d->m_sunLocator, SLOT(update()) ); d->m_pluginManager.addPositionProviderPlugin(new PlacemarkPositionProviderPlugin(this, this)); d->m_pluginManager.addPositionProviderPlugin(new RouteSimulationPositionProviderPlugin(this, this)); } MarbleModel::~MarbleModel() { delete d; mDebug() << "Model deleted:" << this; } BookmarkManager *MarbleModel::bookmarkManager() { return &d->m_bookmarkManager; } QString MarbleModel::mapThemeId() const { QString mapThemeId; if (d->m_mapTheme) mapThemeId = d->m_mapTheme->head()->mapThemeId(); return mapThemeId; } GeoSceneDocument *MarbleModel::mapTheme() { return d->m_mapTheme; } const GeoSceneDocument *MarbleModel::mapTheme() const { return d->m_mapTheme; } // Set a particular theme for the map and load the appropriate tile level. // If the tiles (for the lowest tile level) haven't been created already // then create them here and now. // // FIXME: Move the tile creation dialogs out of this function. Change // them into signals instead. // FIXME: Get rid of 'currentProjection' here. It's totally misplaced. // void MarbleModel::setMapThemeId( const QString &mapThemeId ) { if ( !mapThemeId.isEmpty() && mapThemeId == this->mapThemeId() ) return; GeoSceneDocument *mapTheme = MapThemeManager::loadMapTheme( mapThemeId ); setMapTheme( mapTheme ); } void MarbleModel::setMapTheme( GeoSceneDocument *document ) { GeoSceneDocument *mapTheme = document; if ( !mapTheme ) { // Check whether the previous theme works if ( d->m_mapTheme ){ qWarning() << "Selected theme doesn't work, so we stick to the previous one"; return; } // Fall back to default theme QString defaultTheme = "earth/srtm/srtm.dgml"; qWarning() << "Falling back to default theme:" << defaultTheme; mapTheme = MapThemeManager::loadMapTheme( defaultTheme ); } // If this last resort doesn't work either shed a tear and exit if ( !mapTheme ) { qWarning() << "Couldn't find a valid DGML map."; return; } // find the list of previous theme's geodata QList currentDatasets; if ( d->m_mapTheme ) { for ( GeoSceneLayer *layer: d->m_mapTheme->map()->layers() ) { if ( layer->backend() != dgml::dgmlValue_geodata && layer->backend() != dgml::dgmlValue_vector ) continue; // look for documents for ( GeoSceneAbstractDataset *dataset: layer->datasets() ) { GeoSceneGeodata *data = dynamic_cast( dataset ); Q_ASSERT( data ); currentDatasets << *data; } } } delete d->m_mapTheme; d->m_mapTheme = mapTheme; addDownloadPolicies( d->m_mapTheme ); // Some output to show how to use this stuff ... mDebug() << "DGML2 Name : " << d->m_mapTheme->head()->name(); /* mDebug() << "DGML2 Description: " << d->m_mapTheme->head()->description(); if ( d->m_mapTheme->map()->hasTextureLayers() ) mDebug() << "Contains texture layers! "; else mDebug() << "Does not contain any texture layers! "; mDebug() << "Number of SRTM textures: " << d->m_mapTheme->map()->layer("srtm")->datasets().count(); if ( d->m_mapTheme->map()->hasVectorLayers() ) mDebug() << "Contains vector layers! "; else mDebug() << "Does not contain any vector layers! "; */ //Don't change the planet unless we have to... qreal const radiusAttributeValue = d->m_mapTheme->head()->radius(); if( d->m_mapTheme->head()->target().toLower() != d->m_planet.id() || radiusAttributeValue != d->m_planet.radius() ) { mDebug() << "Changing Planet"; d->m_planet = Magrathea::construct( d->m_mapTheme->head()->target().toLower() ); if ( radiusAttributeValue > 0.0 ) { d->m_planet.setRadius( radiusAttributeValue ); } sunLocator()->setPlanet( &d->m_planet ); } QStringList fileList; QStringList propertyList; QList styleList; QList renderOrderList; bool skip = false; bool sourceFileMatch = false; int datasetIndex = -1; for ( GeoSceneLayer *layer: d->m_mapTheme->map()->layers() ) { if ( layer->backend() != dgml::dgmlValue_geodata && layer->backend() != dgml::dgmlValue_vector ) continue; // look for datasets which are different from currentDatasets for ( const GeoSceneAbstractDataset *dataset: layer->datasets() ) { const GeoSceneGeodata *data = dynamic_cast( dataset ); Q_ASSERT( data ); skip = false; sourceFileMatch = false; for ( int i = 0; i < currentDatasets.size(); ++i ) { if ( currentDatasets[i] == *data ) { currentDatasets.removeAt( i ); skip = true; break; } /** * If the sourcefile of data matches any in the currentDatasets then there * is no need to parse the file again just update the style * i.e. and values of already parsed file. assignNewStyle() does that */ if ( currentDatasets[i].sourceFile() == data->sourceFile() ) { sourceFileMatch = true; datasetIndex = i; } } if ( skip ) { continue; } QString filename = data->sourceFile(); QString property = data->property(); QPen pen = data->pen(); QBrush brush = data->brush(); GeoDataStyle::Ptr style; int renderOrder = data->renderOrder(); /** * data->colors() are the colorMap values from dgml file. If this is not * empty then we are supposed to assign every placemark a different style * by giving it a color from colorMap values based on color index * of that placemark. See assignFillColors() for details. So, we need to * send an empty style to fileManeger otherwise the FileLoader::createFilterProperties() * will overwrite the parsed value of color index ( GeoDataPolyStyle::d->m_colorIndex ). */ if ( data->colors().isEmpty() ) { GeoDataLineStyle lineStyle( pen.color() ); lineStyle.setPenStyle( pen.style() ); lineStyle.setWidth( pen.width() ); GeoDataPolyStyle polyStyle( brush.color() ); polyStyle.setFill( true ); style = GeoDataStyle::Ptr(new GeoDataStyle); style->setLineStyle( lineStyle ); style->setPolyStyle( polyStyle ); style->setId(QStringLiteral("default")); } if ( sourceFileMatch && !currentDatasets[datasetIndex].colors().isEmpty() ) { /** * if new theme file doesn't specify any colorMap for data * then assignNewStyle otherwise assignFillColors. */ currentDatasets.removeAt( datasetIndex ); if ( style ) { qDebug() << "setMapThemeId-> color: " << style->polyStyle().color() << " file: " << filename; d->assignNewStyle( filename, style ); style = GeoDataStyle::Ptr(); } else { d->assignFillColors( data->sourceFile() ); } } else { fileList << filename; propertyList << property; styleList << style; renderOrderList << renderOrder; } } } // unload old currentDatasets which are not part of the new map for(const GeoSceneGeodata &data: currentDatasets) { d->m_fileManager.removeFile( data.sourceFile() ); } // load new datasets for ( int i = 0 ; i < fileList.size(); ++i ) { d->m_fileManager.addFile( fileList.at(i), propertyList.at(i), styleList.at(i), MapDocument, renderOrderList.at(i) ); } mDebug() << "THEME CHANGED: ***" << mapTheme->head()->mapThemeId(); emit themeChanged( mapTheme->head()->mapThemeId() ); } void MarbleModelPrivate::addHighlightStyle(GeoDataDocument* doc) { if ( doc ) { /** * Add a highlight style to GeoDataDocument if *the theme file specifies any highlight color. */ QColor highlightBrushColor = m_mapTheme->map()->highlightBrushColor(); QColor highlightPenColor = m_mapTheme->map()->highlightPenColor(); GeoDataStyle::Ptr highlightStyle(new GeoDataStyle); highlightStyle->setId(QStringLiteral("highlight")); if ( highlightBrushColor.isValid() ) { GeoDataPolyStyle highlightPolyStyle; highlightPolyStyle.setColor( highlightBrushColor ); highlightPolyStyle.setFill( true ); highlightStyle->setPolyStyle( highlightPolyStyle ); } if ( highlightPenColor.isValid() ) { GeoDataLineStyle highlightLineStyle( highlightPenColor ); highlightStyle->setLineStyle( highlightLineStyle ); } if ( highlightBrushColor.isValid() || highlightPenColor.isValid() ) { GeoDataStyleMap styleMap = doc->styleMap(QStringLiteral("default-map")); styleMap.insert(QStringLiteral("highlight"), QLatin1Char('#') + highlightStyle->id()); doc->addStyle( highlightStyle ); doc->addStyleMap( styleMap ); } } } void MarbleModelPrivate::assignNewStyle( const QString &filePath, const GeoDataStyle::Ptr &style ) { GeoDataDocument *doc = m_fileManager.at( filePath ); Q_ASSERT( doc ); GeoDataStyleMap styleMap; styleMap.setId(QStringLiteral("default-map")); styleMap.insert(QStringLiteral("normal"), QLatin1Char('#') + style->id()); doc->addStyleMap( styleMap ); doc->addStyle( style ); addHighlightStyle( doc ); const QString styleUrl = QLatin1Char('#') + styleMap.id(); QVector::iterator iter = doc->begin(); QVector::iterator const end = doc->end(); for ( ; iter != end; ++iter ) { - if ( (*iter)->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = static_cast( *iter ); - if ( placemark ) { - if ( placemark->geometry()->nodeType() != GeoDataTypes::GeoDataTrackType && - placemark->geometry()->nodeType() != GeoDataTypes::GeoDataPointType ) - { - placemark->setStyleUrl(styleUrl); - } + if (auto placemark = geodata_cast(*iter)) { + if (!geodata_cast(placemark->geometry()) && + !geodata_cast(placemark->geometry())) + { + placemark->setStyleUrl(styleUrl); } } } } void MarbleModel::home( qreal &lon, qreal &lat, int& zoom ) const { d->m_homePoint.geoCoordinates( lon, lat, GeoDataCoordinates::Degree ); zoom = d->m_homeZoom; } void MarbleModel::setHome( qreal lon, qreal lat, int zoom ) { d->m_homePoint = GeoDataCoordinates( lon, lat, 0, GeoDataCoordinates::Degree ); d->m_homeZoom = zoom; emit homeChanged( d->m_homePoint ); } void MarbleModel::setHome( const GeoDataCoordinates& homePoint, int zoom ) { d->m_homePoint = homePoint; d->m_homeZoom = zoom; emit homeChanged( d->m_homePoint ); } HttpDownloadManager *MarbleModel::downloadManager() { return &d->m_downloadManager; } const HttpDownloadManager *MarbleModel::downloadManager() const { return &d->m_downloadManager; } GeoDataTreeModel *MarbleModel::treeModel() { return &d->m_treeModel; } const GeoDataTreeModel *MarbleModel::treeModel() const { return &d->m_treeModel; } QAbstractItemModel *MarbleModel::placemarkModel() { return &d->m_placemarkProxyModel; } const QAbstractItemModel *MarbleModel::placemarkModel() const { return &d->m_placemarkProxyModel; } QAbstractItemModel *MarbleModel::groundOverlayModel() { return &d->m_groundOverlayProxyModel; } const QAbstractItemModel *MarbleModel::groundOverlayModel() const { return &d->m_groundOverlayProxyModel; } QItemSelectionModel *MarbleModel::placemarkSelectionModel() { return &d->m_placemarkSelectionModel; } PositionTracking *MarbleModel::positionTracking() const { return &d->m_positionTracking; } FileManager *MarbleModel::fileManager() { return &d->m_fileManager; } qreal MarbleModel::planetRadius() const { return d->m_planet.radius(); } QString MarbleModel::planetName() const { return d->m_planet.name(); } QString MarbleModel::planetId() const { return d->m_planet.id(); } MarbleClock *MarbleModel::clock() { return &d->m_clock; } const MarbleClock *MarbleModel::clock() const { return &d->m_clock; } SunLocator *MarbleModel::sunLocator() { return &d->m_sunLocator; } const SunLocator *MarbleModel::sunLocator() const { return &d->m_sunLocator; } quint64 MarbleModel::persistentTileCacheLimit() const { return d->m_storageWatcher.cacheLimit() / 1024; } void MarbleModel::clearPersistentTileCache() { d->m_storagePolicy.clearCache(); // Now create base tiles again if needed if ( d->m_mapTheme->map()->hasTextureLayers() || d->m_mapTheme->map()->hasVectorLayers() ) { // If the tiles aren't already there, put up a progress dialog // while creating them. // As long as we don't have an Layer Management Class we just lookup // the name of the layer that has the same name as the theme ID QString themeID = d->m_mapTheme->head()->theme(); const GeoSceneLayer *layer = static_cast( d->m_mapTheme->map()->layer( themeID ) ); const GeoSceneTileDataset *texture = static_cast( layer->groundDataset() ); QString sourceDir = texture->sourceDir(); QString installMap = texture->installMap(); QString role = d->m_mapTheme->map()->layer( themeID )->role(); if ( !TileLoader::baseTilesAvailable( *texture ) && !installMap.isEmpty() ) { mDebug() << "Base tiles not available. Creating Tiles ... \n" << "SourceDir: " << sourceDir << "InstallMap:" << installMap; MarbleDirs::debug(); TileCreator *tileCreator = new TileCreator( sourceDir, installMap, (role == QLatin1String("dem")) ? "true" : "false" ); tileCreator->setTileFormat( texture->fileFormat().toLower() ); QPointer tileCreatorDlg = new TileCreatorDialog( tileCreator, 0 ); tileCreatorDlg->setSummary( d->m_mapTheme->head()->name(), d->m_mapTheme->head()->description() ); tileCreatorDlg->exec(); qDebug("Tile creation completed"); delete tileCreatorDlg; } } } void MarbleModel::setPersistentTileCacheLimit(quint64 kiloBytes) { d->m_storageWatcher.setCacheLimit( kiloBytes * 1024 ); if( kiloBytes != 0 ) { if( !d->m_storageWatcher.isRunning() ) d->m_storageWatcher.start( QThread::IdlePriority ); } else { d->m_storageWatcher.quit(); } // TODO: trigger update } void MarbleModel::setTrackedPlacemark( const GeoDataPlacemark *placemark ) { d->m_trackedPlacemark = placemark; emit trackedPlacemarkChanged( placemark ); } const GeoDataPlacemark* MarbleModel::trackedPlacemark() const { return d->m_trackedPlacemark; } const PluginManager* MarbleModel::pluginManager() const { return &d->m_pluginManager; } PluginManager* MarbleModel::pluginManager() { return &d->m_pluginManager; } const Planet *MarbleModel::planet() const { return &d->m_planet; } void MarbleModel::addDownloadPolicies( const GeoSceneDocument *mapTheme ) { if ( !mapTheme ) return; if ( !mapTheme->map()->hasTextureLayers() && !mapTheme->map()->hasVectorLayers() ) return; // As long as we don't have an Layer Management Class we just lookup // the name of the layer that has the same name as the theme ID const QString themeId = mapTheme->head()->theme(); const GeoSceneLayer * const layer = static_cast( mapTheme->map()->layer( themeId )); if ( !layer ) return; const GeoSceneTileDataset * const texture = static_cast( layer->groundDataset() ); if ( !texture ) return; QList policies = texture->downloadPolicies(); QList::const_iterator pos = policies.constBegin(); QList::const_iterator const end = policies.constEnd(); for (; pos != end; ++pos ) { d->m_downloadManager.addDownloadPolicy( **pos ); } } RoutingManager* MarbleModel::routingManager() { return d->m_routingManager; } const RoutingManager* MarbleModel::routingManager() const { return d->m_routingManager; } void MarbleModel::setClockDateTime( const QDateTime& datetime ) { d->m_clock.setDateTime( datetime ); } QDateTime MarbleModel::clockDateTime() const { return d->m_clock.dateTime(); } int MarbleModel::clockSpeed() const { return d->m_clock.speed(); } void MarbleModel::setClockSpeed( int speed ) { d->m_clock.setSpeed( speed ); } void MarbleModel::setClockTimezone( int timeInSec ) { d->m_clock.setTimezone( timeInSec ); } int MarbleModel::clockTimezone() const { return d->m_clock.timezone(); } QTextDocument * MarbleModel::legend() { return d->m_legend; } void MarbleModel::setLegend( QTextDocument * legend ) { delete d->m_legend; d->m_legend = legend; } void MarbleModel::addGeoDataFile( const QString& filename ) { d->m_fileManager.addFile( filename, filename, GeoDataStyle::Ptr(), UserDocument, true ); } void MarbleModel::addGeoDataString( const QString& data, const QString& key ) { d->m_fileManager.addData( key, data, UserDocument ); } void MarbleModel::removeGeoData( const QString& fileName ) { d->m_fileManager.removeFile( fileName ); } void MarbleModel::updateProperty( const QString &property, bool value ) { for( GeoDataFeature *feature: d->m_treeModel.rootDocument()->featureList()) { - if( feature->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - GeoDataDocument *document = static_cast( feature ); + if (auto document = geodata_cast(feature)) { if( document->property() == property ){ document->setVisible( value ); d->m_treeModel.updateFeature( document ); } } } } void MarbleModelPrivate::assignFillColors( const QString &filePath ) { for( GeoSceneLayer *layer: m_mapTheme->map()->layers() ) { if ( layer->backend() == dgml::dgmlValue_geodata || layer->backend() == dgml::dgmlValue_vector ) { for( GeoSceneAbstractDataset *dataset: layer->datasets() ) { GeoSceneGeodata *data = static_cast( dataset ); if ( data ) { if ( data->sourceFile() == filePath ) { GeoDataDocument *doc = m_fileManager.at( filePath ); Q_ASSERT( doc ); addHighlightStyle( doc ); QPen pen = data->pen(); QBrush brush = data->brush(); const QVector colors = data->colors(); GeoDataLineStyle lineStyle( pen.color() ); lineStyle.setPenStyle( pen.style() ); lineStyle.setWidth( pen.width() ); if ( !colors.isEmpty() ) { qreal alpha = data->alpha(); QVector::iterator it = doc->begin(); QVector::iterator const itEnd = doc->end(); for ( ; it != itEnd; ++it ) { GeoDataPlacemark *placemark = dynamic_cast( *it ); if ( placemark ) { GeoDataStyle::Ptr style(new GeoDataStyle); style->setId(QStringLiteral("normal")); style->setLineStyle( lineStyle ); quint8 colorIndex = placemark->style()->polyStyle().colorIndex(); GeoDataPolyStyle polyStyle; // Set the colorIndex so that it's not lost after setting new style. polyStyle.setColorIndex( colorIndex ); QColor color; // color index having value 99 is undefined Q_ASSERT( colors.size() ); if ( colorIndex > colors.size() || ( colorIndex - 1 ) < 0 ) { color = colors[0]; // Assign the first color as default } else { color = colors[colorIndex-1]; } color.setAlphaF( alpha ); polyStyle.setColor( color ); polyStyle.setFill( true ); style->setPolyStyle( polyStyle ); placemark->setStyle( style ); } } } else { GeoDataStyle::Ptr style(new GeoDataStyle); GeoDataPolyStyle polyStyle( brush.color() ); polyStyle.setFill( true ); style->setLineStyle( lineStyle ); style->setPolyStyle( polyStyle ); style->setId(QStringLiteral("default")); GeoDataStyleMap styleMap; styleMap.setId(QStringLiteral("default-map")); styleMap.insert(QStringLiteral("normal"), QLatin1Char('#') + style->id()); doc->addStyle( style ); doc->addStyleMap( styleMap ); const QString styleUrl = QLatin1Char('#') + styleMap.id(); QVector::iterator iter = doc->begin(); QVector::iterator const end = doc->end(); for ( ; iter != end; ++iter ) { - if ( (*iter)->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = dynamic_cast( *iter ); - Q_ASSERT( placemark ); - if ( placemark->geometry()->nodeType() != GeoDataTypes::GeoDataTrackType && - placemark->geometry()->nodeType() != GeoDataTypes::GeoDataPointType ) + if (auto placemark = geodata_cast(*iter)) { + if (!geodata_cast(placemark->geometry()) && + !geodata_cast(placemark->geometry())) { placemark->setStyleUrl(styleUrl); } } } } } } } } } } bool MarbleModel::workOffline() const { return d->m_workOffline; } void MarbleModel::setWorkOffline( bool workOffline ) { if ( d->m_workOffline != workOffline ) { downloadManager()->setDownloadEnabled( !workOffline ); d->m_workOffline = workOffline; emit workOfflineChanged(); } } ElevationModel* MarbleModel::elevationModel() { return &d->m_elevationModel; } const ElevationModel* MarbleModel::elevationModel() const { return &d->m_elevationModel; } } #include "moc_MarbleModel.cpp" diff --git a/src/lib/marble/MarbleWidgetPopupMenu.cpp b/src/lib/marble/MarbleWidgetPopupMenu.cpp index 6b37a4cb9..b99a46100 100644 --- a/src/lib/marble/MarbleWidgetPopupMenu.cpp +++ b/src/lib/marble/MarbleWidgetPopupMenu.cpp @@ -1,920 +1,919 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2006-2007 Torsten Rahn // Copyright 2007 Inge Wallin // Copyright 2012 Illya Kovalevskyy // Copyright 2014 Gábor Péterffy // // Self #include "MarbleWidgetPopupMenu.h" // Marble #include "AbstractDataPluginItem.h" #include "AbstractFloatItem.h" #include "MarbleAboutDialog.h" #include "MarbleDirs.h" #include "MarbleWidget.h" #include "MarbleModel.h" #include "GeoDataExtendedData.h" #include "GeoDataFolder.h" #include "GeoDataPlacemark.h" #include "GeoDataLookAt.h" #include "GeoDataData.h" #include "GeoDataSnippet.h" #include "GeoDataStyle.h" #include "GeoDataBalloonStyle.h" #include "GeoDataIconStyle.h" #include "GeoDataPoint.h" -#include "GeoDataTypes.h" #include "GeoDataPhotoOverlay.h" #include "GeoSceneDocument.h" #include "GeoSceneHead.h" #include "MarbleClock.h" #include "MarbleDebug.h" #include "PopupLayer.h" #include "Planet.h" #include "routing/RoutingManager.h" #include "routing/RoutingLayer.h" #include "routing/RouteRequest.h" #include "EditBookmarkDialog.h" #include "BookmarkManager.h" #include "ReverseGeocodingRunnerManager.h" #include "TemplateDocument.h" #include "OsmPlacemarkData.h" #include "StyleBuilder.h" // Qt #include #include #include #include #include #include #include #include namespace Marble { /* TRANSLATOR Marble::MarbleWidgetPopupMenu */ class Q_DECL_HIDDEN MarbleWidgetPopupMenu::Private { public: const MarbleModel *const m_model; MarbleWidget *const m_widget; QVector m_featurelist; QList m_itemList; QMenu m_lmbMenu; QMenu m_rmbMenu; QAction *m_infoDialogAction; QAction *m_directionsFromHereAction; QAction *m_directionsToHereAction; QAction *const m_copyCoordinateAction; QAction *m_rmbExtensionPoint; ReverseGeocodingRunnerManager m_runnerManager; QPoint m_mousePosition; public: Private( MarbleWidget *widget, const MarbleModel *model, MarbleWidgetPopupMenu* parent ); QMenu* createInfoBoxMenu(QWidget *parent); /** * Returns the geo coordinates of the mouse pointer at the last right button menu. * You must not pass 0 as coordinates parameter. The result indicates whether the * coordinates are valid, which will be true if the right button menu was opened at least once. */ GeoDataCoordinates mouseCoordinates( QAction* dataContainer ) const; static QString filterEmptyShortDescription( const QString &description ); void setupDialogOsm( PopupLayer *popup, const GeoDataPlacemark* placemark ); void setupDialogSatellite( const GeoDataPlacemark *placemark ); static void setupDialogCity( PopupLayer *popup, const GeoDataPlacemark *placemark ); static void setupDialogNation( PopupLayer *popup, const GeoDataPlacemark *placemark ); static void setupDialogGeoPlaces( PopupLayer *popup, const GeoDataPlacemark *placemark ); static void setupDialogSkyPlaces( PopupLayer *popup, const GeoDataPlacemark *placemark ); static void setupDialogPhotoOverlay( PopupLayer *popup, const GeoDataPhotoOverlay *overlay); }; MarbleWidgetPopupMenu::Private::Private( MarbleWidget *widget, const MarbleModel *model, MarbleWidgetPopupMenu* parent ) : m_model(model), m_widget(widget), m_lmbMenu( m_widget ), m_rmbMenu( m_widget ), m_directionsFromHereAction( 0 ), m_directionsToHereAction( 0 ), m_copyCoordinateAction(new QAction(QIcon(QStringLiteral(":/icons/copy-coordinates.png")), tr("Copy Coordinates"), parent)), m_rmbExtensionPoint( 0 ), m_runnerManager( model ) { // Property actions (Left mouse button) m_infoDialogAction = new QAction( parent ); m_infoDialogAction->setData( 0 ); // Tool actions (Right mouse button) m_directionsFromHereAction = new QAction( tr( "Directions &from here" ), parent ); m_directionsToHereAction = new QAction( tr( "Directions &to here" ), parent ); RouteRequest* request = m_widget->model()->routingManager()->routeRequest(); if ( request ) { m_directionsFromHereAction->setIcon( QIcon( request->pixmap( 0, 16 ) ) ); int const lastIndex = qMax( 1, request->size()-1 ); m_directionsToHereAction->setIcon( QIcon( request->pixmap( lastIndex, 16 ) ) ); } QAction* addBookmark = new QAction( QIcon(QStringLiteral(":/icons/bookmark-new.png")), tr( "Add &Bookmark" ), parent ); QAction* fullscreenAction = new QAction( tr( "&Full Screen Mode" ), parent ); fullscreenAction->setCheckable( true ); QAction* aboutDialogAction = new QAction(QIcon(QStringLiteral(":/icons/marble.png")), tr("&About"), parent); QMenu* infoBoxMenu = createInfoBoxMenu(m_widget); const bool smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; if ( !smallScreen ) { m_rmbExtensionPoint = m_rmbMenu.addSeparator(); } m_rmbMenu.addAction( m_directionsFromHereAction ); m_rmbMenu.addAction( m_directionsToHereAction ); m_rmbMenu.addSeparator(); m_rmbMenu.addAction( addBookmark ); if ( !smallScreen ) { m_rmbMenu.addAction( m_copyCoordinateAction ); } m_rmbMenu.addAction(QIcon(QStringLiteral(":/icons/addressbook-details.png")), tr("&Address Details"), parent, SLOT(startReverseGeocoding())); m_rmbMenu.addSeparator(); m_rmbMenu.addMenu( infoBoxMenu ); if ( !smallScreen ) { m_rmbMenu.addAction( aboutDialogAction ); } else { m_rmbMenu.addAction( fullscreenAction ); } parent->connect( &m_lmbMenu, SIGNAL(aboutToHide()), SLOT(resetMenu()) ); parent->connect( m_directionsFromHereAction, SIGNAL(triggered()), SLOT(directionsFromHere()) ); parent->connect( m_directionsToHereAction, SIGNAL(triggered()), SLOT(directionsToHere()) ); parent->connect( addBookmark, SIGNAL(triggered()), SLOT(addBookmark()) ); parent->connect( aboutDialogAction, SIGNAL(triggered()), SLOT(slotAboutDialog()) ); parent->connect( m_copyCoordinateAction, SIGNAL(triggered()), SLOT(slotCopyCoordinates()) ); parent->connect( m_infoDialogAction, SIGNAL(triggered()), SLOT(slotInfoDialog()) ); parent->connect( fullscreenAction, SIGNAL(triggered(bool)), parent, SLOT(toggleFullscreen(bool)) ); parent->connect( &m_runnerManager, SIGNAL(reverseGeocodingFinished(GeoDataCoordinates,GeoDataPlacemark)), parent, SLOT(showAddressInformation(GeoDataCoordinates,GeoDataPlacemark)) ); } QString MarbleWidgetPopupMenu::Private::filterEmptyShortDescription(const QString &description) { if(description.isEmpty()) return tr("No description available."); return description; } void MarbleWidgetPopupMenu::Private::setupDialogOsm( PopupLayer *popup, const GeoDataPlacemark *placemark ) { const GeoDataCoordinates location = placemark->coordinate(); popup->setCoordinates(location, Qt::AlignRight | Qt::AlignVCenter); QFile descriptionFile(QStringLiteral(":/marble/webpopup/osm.html")); if (!descriptionFile.open(QIODevice::ReadOnly)) { return; } const QString none = QStringLiteral("none"); QString description = descriptionFile.readAll(); const OsmPlacemarkData& data = placemark->osmData(); if (!data.containsTagKey("addr:street") && !data.containsTagKey("addr:housenumber")){ description.replace(QStringLiteral("
%postcode%"), QStringLiteral("%postcode%")); } TemplateDocument doc(description); doc[QStringLiteral("name")] = data.tagValue(QStringLiteral("name")); QString natural = data.tagValue(QStringLiteral("natural")); if (!natural.isEmpty()) { natural[0] = natural[0].toUpper(); if (natural == QLatin1String("Peak")) { QString elevation = data.tagValue(QStringLiteral("ele")); if (!elevation.isEmpty()) { natural = natural + QLatin1String(" - ") + elevation + QLatin1String(" m"); } } doc[QStringLiteral("details")] = natural; } else { doc[QStringLiteral("detailsVisibility")] = none; } QString amenity; QString shop = data.tagValue(QStringLiteral("shop")); if (!shop.isEmpty()) { shop[0] = shop[0].toUpper(); if (shop == QLatin1String("Clothes")) { QString type = data.tagValue(QStringLiteral("clothes")); if (type.isEmpty()) { type = data.tagValue(QStringLiteral("designation")); } if (!type.isEmpty()) { type[0] = type[0].toUpper(); amenity = QLatin1String("Shop - ") + shop + QLatin1String(" (") + type + QLatin1Char(')'); } } if (amenity.isEmpty()) { amenity = QLatin1String("Shop - ") + shop; } } else { amenity = data.tagValue(QStringLiteral("amenity")); if (!amenity.isEmpty()) { amenity[0] = amenity[0].toUpper(); } } if (!amenity.isEmpty()) { doc[QStringLiteral("amenity")] = amenity; } else { doc[QStringLiteral("amenityVisibility")] = none; } QString cuisine = data.tagValue(QStringLiteral("cuisine")); if (!cuisine.isEmpty()) { cuisine[0] = cuisine[0].toUpper(); doc[QStringLiteral("cuisine")] = cuisine; } else { doc[QStringLiteral("cuisineVisibility")] = none; } QString openingHours = data.tagValue(QStringLiteral("opening_hours")); if (!openingHours.isEmpty()) { doc[QStringLiteral("openinghours")] = openingHours; } else { doc[QStringLiteral("openinghoursVisibility")] = none; } bool hasContactsData = false; const QStringList addressItemKeys = QStringList() << QStringLiteral("street") << QStringLiteral("housenumber") << QStringLiteral("postcode") << QStringLiteral("city"); bool hasAddressItem = false; QStringList addressItems; for (const QString& key: addressItemKeys) { const QString item = data.tagValue(QLatin1String("addr:") + key); if (!item.isEmpty()) { hasAddressItem = true; } addressItems << item; } if (hasAddressItem) { hasContactsData = true; for(int i = 0; i < addressItemKeys.size(); ++i) { doc[addressItemKeys[i]] = addressItems[i]; } } else { doc[QStringLiteral("addressVisibility")] = none; } QString phoneData = data.tagValue(QStringLiteral("phone")); if (!phoneData.isEmpty()) { hasContactsData = true; doc[QStringLiteral("phone")] = phoneData; } else { doc[QStringLiteral("phoneVisibility")] = none; } QString websiteData; auto const tags = QStringList() << "website" << "contact:website" << "facebook" << "contact:facebook" << "url"; for(const QString &tag: tags) { websiteData = data.tagValue(tag); if (!websiteData.isEmpty()) { break; } } if (!websiteData.isEmpty()) { hasContactsData = true; doc[QStringLiteral("website")] = websiteData; } else { doc[QStringLiteral("websiteVisibility")] = none; } if (!hasContactsData) { doc[QStringLiteral("contactVisibility")] = none; } bool hasFacilitiesData = false; const QString wheelchair = data.tagValue(QStringLiteral("wheelchair")); if (!wheelchair.isEmpty()) { hasFacilitiesData = true; doc[QStringLiteral("wheelchair")] = wheelchair; } else { doc[QStringLiteral("wheelchairVisibility")] = none; } const QString internetAccess = data.tagValue(QStringLiteral("internet_access")); if (!internetAccess.isEmpty()) { hasFacilitiesData = true; doc[QStringLiteral("internetaccess")] = internetAccess; } else { doc[QStringLiteral("internetVisibility")] = none; } const QString smoking = data.tagValue(QStringLiteral("smoking")); if (!smoking.isEmpty()) { hasFacilitiesData = true; doc[QStringLiteral("smoking")] = smoking; } else { doc[QStringLiteral("smokingVisibility")] = none; } if (!hasFacilitiesData) { doc[QStringLiteral("facilitiesVisibility")] = none; } const QString flagPath = m_widget->styleBuilder()->createStyle(StyleParameters(placemark))->iconStyle().iconPath(); doc["flag"] = flagPath; popup->setContent(doc.finalText()); } void MarbleWidgetPopupMenu::Private::setupDialogSatellite( const GeoDataPlacemark *placemark ) { PopupLayer *const popup = m_widget->popupLayer(); const GeoDataCoordinates location = placemark->coordinate(m_widget->model()->clockDateTime()); popup->setCoordinates(location, Qt::AlignRight | Qt::AlignVCenter); const QString description = placemark->description(); TemplateDocument doc(description); doc["altitude"] = QString::number(location.altitude(), 'f', 2); doc["latitude"] = location.latToString(); doc["longitude"] = location.lonToString(); popup->setContent(doc.finalText()); } void MarbleWidgetPopupMenu::Private::setupDialogCity( PopupLayer *popup, const GeoDataPlacemark *placemark ) { const GeoDataCoordinates location = placemark->coordinate(); popup->setCoordinates(location, Qt::AlignRight | Qt::AlignVCenter); QFile descriptionFile(QStringLiteral(":/marble/webpopup/city.html")); if (!descriptionFile.open(QIODevice::ReadOnly)) { return; } const QString description = descriptionFile.readAll(); TemplateDocument doc(description); doc["name"] = placemark->name(); QString roleString; const QString role = placemark->role(); if (role == QLatin1String("PPLC")) { roleString = tr("National Capital"); } else if (role == QLatin1String("PPL")) { roleString = tr("City"); } else if (role == QLatin1String("PPLA")) { roleString = tr("State Capital"); } else if (role == QLatin1String("PPLA2")) { roleString = tr("County Capital"); } else if (role == QLatin1String("PPLA3") || role == QLatin1String("PPLA4")) { roleString = tr("Capital"); } else if (role == QLatin1String("PPLF") || role == QLatin1String("PPLG") || role == QLatin1String("PPLL") || role == QLatin1String("PPLQ") || role == QLatin1String("PPLR") || role == QLatin1String("PPLS") || role == QLatin1String("PPLW")) { roleString = tr("Village"); } doc["category"] = roleString; doc["shortDescription"] = filterEmptyShortDescription(placemark->description()); doc["latitude"] = location.latToString(); doc["longitude"] = location.lonToString(); doc["elevation"] = QString::number(location.altitude(), 'f', 2); doc["population"] = QString::number(placemark->population()); doc["country"] = placemark->countryCode(); doc["state"] = placemark->state(); QString dst = QStringLiteral("%1").arg((placemark->extendedData().value(QStringLiteral("gmt")).value().toInt() + placemark->extendedData().value(QStringLiteral("dst")).value().toInt()) / ( double ) 100, 0, 'f', 1 ); // There is an issue about UTC. // It's possible to variants (e.g.): // +1.0 and -1.0, but dst does not have + an the start if (dst.startsWith(QLatin1Char('-'))) { doc["timezone"] = dst; } else { doc["timezone"] = QLatin1Char('+') + dst; } const QString flagPath = MarbleDirs::path( QLatin1String("flags/flag_") + placemark->countryCode().toLower() + QLatin1String(".svg")); doc["flag"] = flagPath; popup->setContent(doc.finalText()); } void MarbleWidgetPopupMenu::Private::setupDialogNation( PopupLayer *popup, const GeoDataPlacemark *index) { const GeoDataCoordinates location = index->coordinate(); popup->setCoordinates(location, Qt::AlignRight | Qt::AlignVCenter); QFile descriptionFile(QStringLiteral(":/marble/webpopup/nation.html")); if (!descriptionFile.open(QIODevice::ReadOnly)) { return; } const QString description = descriptionFile.readAll(); TemplateDocument doc(description); doc["name"] = index->name(); doc["shortDescription"] = filterEmptyShortDescription(index->description()); doc["latitude"] = location.latToString(); doc["longitude"] = location.lonToString(); doc["elevation"] = QString::number(location.altitude(), 'f', 2); doc["population"] = QString::number(index->population()); doc["area"] = QString::number(index->area(), 'f', 2); const QString flagPath = MarbleDirs::path(QString("flags/flag_%1.svg").arg(index->countryCode().toLower()) ); doc["flag"] = flagPath; popup->setContent(doc.finalText()); } void MarbleWidgetPopupMenu::Private::setupDialogGeoPlaces( PopupLayer *popup, const GeoDataPlacemark *index) { const GeoDataCoordinates location = index->coordinate(); popup->setCoordinates(location, Qt::AlignRight | Qt::AlignVCenter); QFile descriptionFile(QStringLiteral(":/marble/webpopup/geoplace.html")); if (!descriptionFile.open(QIODevice::ReadOnly)) { return; } const QString description = descriptionFile.readAll(); TemplateDocument doc(description); doc["name"] = index->name(); doc["latitude"] = location.latToString(); doc["longitude"] = location.lonToString(); doc["elevation"] = QString::number(location.altitude(), 'f', 2); doc["shortDescription"] = filterEmptyShortDescription(index->description()); popup->setContent(doc.finalText()); } void MarbleWidgetPopupMenu::Private::setupDialogSkyPlaces( PopupLayer *popup, const GeoDataPlacemark *index) { const GeoDataCoordinates location = index->coordinate(); popup->setCoordinates(location, Qt::AlignRight | Qt::AlignVCenter); QFile descriptionFile(QStringLiteral(":/marble/webpopup/skyplace.html")); if (!descriptionFile.open(QIODevice::ReadOnly)) { return; } const QString description = descriptionFile.readAll(); TemplateDocument doc(description); doc["name"] = index->name(); doc["latitude"] = GeoDataCoordinates::latToString( location.latitude(), GeoDataCoordinates::Astro, GeoDataCoordinates::Radian, -1, 'f'); doc["longitude"] = GeoDataCoordinates::lonToString( location.longitude(), GeoDataCoordinates::Astro, GeoDataCoordinates::Radian, -1, 'f'); doc["shortDescription"] = filterEmptyShortDescription(index->description()); popup->setContent(doc.finalText()); } void MarbleWidgetPopupMenu::Private::setupDialogPhotoOverlay( PopupLayer *popup, const GeoDataPhotoOverlay *index ) { const GeoDataCoordinates location = index->point().coordinates(); popup->setCoordinates(location, Qt::AlignRight | Qt::AlignVCenter); QFile descriptionFile(QStringLiteral(":/marble/webpopup/photooverlay.html")); if ( !descriptionFile.open(QIODevice::ReadOnly) ) { return; } const QString description = descriptionFile.readAll(); TemplateDocument doc(description); doc["name"] = index->name(); doc["latitude"] = location.latToString(); doc["longitude"] = location.lonToString(); doc["elevation"] = QString::number(location.altitude(), 'f', 2); doc["shortDescription"] = filterEmptyShortDescription(index->description()); doc["source"] = index->absoluteIconFile(); doc["width"] = QString::number(200); doc["height"] = QString::number(100); QString const basePath = index->resolvePath("."); QUrl const baseUrl = (basePath != QLatin1String(".")) ? QUrl::fromLocalFile(basePath + QLatin1Char('/')) : QUrl(); popup->setContent(doc.finalText(), baseUrl ); } MarbleWidgetPopupMenu::MarbleWidgetPopupMenu(MarbleWidget *widget, const MarbleModel *model) : QObject(widget), d( new Private( widget, model, this ) ) { // nothing to do } MarbleWidgetPopupMenu::~MarbleWidgetPopupMenu() { delete d; } QMenu* MarbleWidgetPopupMenu::Private::createInfoBoxMenu(QWidget* parent) { QMenu* menu = new QMenu(tr("&Info Boxes"), parent); QList floatItemList = m_widget->floatItems(); QList::const_iterator iter = floatItemList.constBegin(); QList::const_iterator const end = floatItemList.constEnd(); for (; iter != end; ++iter ) { menu->addAction( (*iter)->action() ); } return menu; } void MarbleWidgetPopupMenu::showLmbMenu( int xpos, int ypos ) { bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; if ( smallScreen ) { showRmbMenu( xpos, ypos ); return; } d->m_mousePosition.setX(xpos); d->m_mousePosition.setY(ypos); const QPoint curpos = QPoint( xpos, ypos ); d->m_featurelist = d->m_widget->whichFeatureAt( curpos ); int actionidx = 1; QVector::const_iterator it = d->m_featurelist.constBegin(); QVector::const_iterator const itEnd = d->m_featurelist.constEnd(); for (; it != itEnd; ++it ) { QString name = (*it)->name(); QPixmap icon = QPixmap::fromImage( ( *it)->style()->iconStyle().icon() ); d->m_infoDialogAction->setData( actionidx ); d->m_infoDialogAction->setText( name ); d->m_infoDialogAction->setIcon( icon ); // Insert as first action in the menu QAction *firstAction = 0; if( !d->m_lmbMenu.actions().isEmpty() ) { firstAction = d->m_lmbMenu.actions().first(); } d->m_lmbMenu.insertAction( firstAction, d->m_infoDialogAction ); actionidx++; } d->m_itemList = d->m_widget->whichItemAt( curpos ); QList::const_iterator itW = d->m_itemList.constBegin(); QList::const_iterator const itWEnd = d->m_itemList.constEnd(); for (; itW != itWEnd; ++itW ) { for ( QAction* action: (*itW)->actions() ) { d->m_lmbMenu.addAction( action ); } } switch ( d->m_lmbMenu.actions().size() ) { case 0: // nothing to do, ignore break; case 1: // one action? perform immediately d->m_lmbMenu.actions().first()->activate( QAction::Trigger ); d->m_lmbMenu.clear(); break; default: d->m_lmbMenu.popup( d->m_widget->mapToGlobal( curpos ) ); } } void MarbleWidgetPopupMenu::showRmbMenu( int xpos, int ypos ) { qreal lon, lat; const bool visible = d->m_widget->geoCoordinates( xpos, ypos, lon, lat, GeoDataCoordinates::Radian ); if ( !visible ) return; d->m_mousePosition.setX(xpos); d->m_mousePosition.setY(ypos); QPoint curpos = QPoint( xpos, ypos ); d->m_copyCoordinateAction->setData( curpos ); bool const showDirectionButtons = d->m_widget->routingLayer() && d->m_widget->routingLayer()->isInteractive(); d->m_directionsFromHereAction->setVisible( showDirectionButtons ); d->m_directionsToHereAction->setVisible( showDirectionButtons ); RouteRequest* request = d->m_widget->model()->routingManager()->routeRequest(); if ( request ) { int const lastIndex = qMax( 1, request->size()-1 ); d->m_directionsToHereAction->setIcon( QIcon( request->pixmap( lastIndex, 16 ) ) ); } d->m_rmbMenu.popup( d->m_widget->mapToGlobal( curpos ) ); } void MarbleWidgetPopupMenu::resetMenu() { d->m_lmbMenu.clear(); } void MarbleWidgetPopupMenu::slotInfoDialog() { QAction *action = qobject_cast( sender() ); if ( action == 0 ) { mDebug() << "Warning: slotInfoDialog should be called by a QAction signal"; return; } int actionidx = action->data().toInt(); if ( actionidx > 0 ) { const GeoDataPlacemark *placemark = dynamic_cast(d->m_featurelist.at( actionidx -1 )); const GeoDataPhotoOverlay *overlay = dynamic_cast(d->m_featurelist.at( actionidx - 1 )); PopupLayer* popup = d->m_widget->popupLayer(); bool isSatellite = false; bool isCity = false; bool isNation = false; const OsmPlacemarkData& data = placemark->osmData(); bool hasOsmData = false; QStringList recognizedTags; recognizedTags << "name" << "amenity" << "cuisine" << "opening_hours"; recognizedTags << "addr:street" << "addr:housenumber" << "addr:postcode"; recognizedTags << "addr:city" << "phone" << "wheelchair" << "internet_access"; recognizedTags << "smoking" << "website" << "contact:website" << "facebook"; recognizedTags << "contact:facebook" << "url"; for(const QString &tag: recognizedTags) { if (data.containsTagKey(tag)) { hasOsmData = true; break; } } if ( placemark ) { isSatellite = (placemark->visualCategory() == GeoDataPlacemark::Satellite); isCity = (placemark->visualCategory() >= GeoDataPlacemark::SmallCity && placemark->visualCategory() <= GeoDataPlacemark::LargeNationCapital); isNation = (placemark->visualCategory() == GeoDataPlacemark::Nation); } bool isSky = false; if ( d->m_widget->model()->mapTheme() ) { isSky = d->m_widget->model()->mapTheme()->head()->target() == QLatin1String("sky"); } popup->setSize(QSizeF(420, 420)); if (hasOsmData){ d->setupDialogOsm( popup, placemark ); } else if (isSatellite) { d->setupDialogSatellite( placemark ); } else if (isCity) { Private::setupDialogCity( popup, placemark ); } else if (isNation) { Private::setupDialogNation( popup, placemark ); } else if (isSky) { Private::setupDialogSkyPlaces( popup, placemark ); } else if ( overlay ) { Private::setupDialogPhotoOverlay( popup, overlay ); } else if ( placemark && placemark->role().isEmpty() ) { popup->setContent( placemark->description() ); } else if ( placemark ) { Private::setupDialogGeoPlaces( popup, placemark ); } if ( placemark ) { if ( placemark->style() == 0 ) { popup->setBackgroundColor(QColor(Qt::white)); popup->setTextColor(QColor(Qt::black)); return; } if ( placemark->style()->balloonStyle().displayMode() == GeoDataBalloonStyle::Hide ) { popup->setVisible(false); return; } QString content = placemark->style()->balloonStyle().text(); if (content.length() > 0) { content.replace(QStringLiteral("$[name]"), placemark->name(), Qt::CaseInsensitive); content.replace(QStringLiteral("$[description]"), placemark->description(), Qt::CaseInsensitive); content.replace(QStringLiteral("$[address]"), placemark->address(), Qt::CaseInsensitive); // @TODO: implement the line calculation, so that snippet().maxLines actually has effect. content.replace(QStringLiteral("$[snippet]"), placemark->snippet().text(), Qt::CaseInsensitive); content.replace(QStringLiteral("$[id]"), placemark->id(), Qt::CaseInsensitive); QString const basePath = placemark->resolvePath("."); QUrl const baseUrl = (basePath != QLatin1String(".")) ? QUrl::fromLocalFile(basePath + QLatin1Char('/')) : QUrl(); popup->setContent(content, baseUrl ); } popup->setBackgroundColor(placemark->style()->balloonStyle().backgroundColor()); popup->setTextColor(placemark->style()->balloonStyle().textColor()); } popup->popup(); } } void MarbleWidgetPopupMenu::slotCopyCoordinates() { const GeoDataCoordinates coordinates = d->mouseCoordinates( d->m_copyCoordinateAction ); if ( coordinates.isValid() ) { const qreal longitude_degrees = coordinates.longitude(GeoDataCoordinates::Degree); const qreal latitude_degrees = coordinates.latitude(GeoDataCoordinates::Degree); // importing this representation into Marble does not show anything, // but Merkaartor shows the point const QString kmlRepresentation = QString::fromLatin1( "\n" "\n" "\n" " \n" // " \n" " \n" " %1,%2\n" " \n" " \n" "\n" "\n" ).arg(longitude_degrees, 0, 'f', 10).arg(latitude_degrees, 0, 'f', 10); // importing this data into Marble and Merkaartor works const QString gpxRepresentation = QString::fromLatin1( "\n" "\n" " \n" // " %3\n" // " \n" // " %4\n" " \n" "\n" ).arg(latitude_degrees, 0, 'f', 10).arg(longitude_degrees, 0, 'f', 10); QString positionString = coordinates.toString(); QMimeData * const myMimeData = new QMimeData(); myMimeData->setText(positionString); myMimeData->setData(QLatin1String("application/vnd.google-earth.kml+xml"), kmlRepresentation.toUtf8()); myMimeData->setData(QLatin1String("application/gpx+xml"), gpxRepresentation.toUtf8()); QClipboard * const clipboard = QApplication::clipboard(); clipboard->setMimeData(myMimeData); } } void MarbleWidgetPopupMenu::slotAboutDialog() { QPointer dialog = new MarbleAboutDialog( d->m_widget ); dialog->exec(); delete dialog; } void MarbleWidgetPopupMenu::addAction( Qt::MouseButton button, QAction* action ) { if ( button == Qt::RightButton ) { d->m_rmbMenu.insertAction( d->m_rmbExtensionPoint, action ); } else { d->m_lmbMenu.addAction( action ); } } void MarbleWidgetPopupMenu::directionsFromHere() { RouteRequest* request = d->m_widget->model()->routingManager()->routeRequest(); if ( request ) { const GeoDataCoordinates coordinates = d->mouseCoordinates( d->m_copyCoordinateAction ); if ( coordinates.isValid() ) { if ( request->size() > 0 ) { request->setPosition( 0, coordinates ); } else { request->append( coordinates ); } d->m_widget->model()->routingManager()->retrieveRoute(); } } } void MarbleWidgetPopupMenu::directionsToHere() { RouteRequest* request = d->m_widget->model()->routingManager()->routeRequest(); if ( request ) { const GeoDataCoordinates coordinates = d->mouseCoordinates( d->m_copyCoordinateAction ); if ( coordinates.isValid() ) { if ( request->size() > 1 ) { request->setPosition( request->size()-1, coordinates ); } else { request->append( coordinates ); } d->m_widget->model()->routingManager()->retrieveRoute(); } } } GeoDataCoordinates MarbleWidgetPopupMenu::Private::mouseCoordinates( QAction* dataContainer ) const { if ( !dataContainer ) { return GeoDataCoordinates(); } - if ( !m_featurelist.isEmpty() && m_featurelist.first()->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { + if ( !m_featurelist.isEmpty() && geodata_cast(m_featurelist.first())) { const GeoDataPlacemark * placemark = static_cast( m_featurelist.first() ); return placemark->coordinate( m_model->clock()->dateTime() ); } else { QPoint p = dataContainer->data().toPoint(); qreal lat( 0.0 ), lon( 0.0 ); const bool valid = m_widget->geoCoordinates( p.x(), p.y(), lon, lat, GeoDataCoordinates::Radian ); if ( valid ) { return GeoDataCoordinates( lon, lat ); } } return GeoDataCoordinates(); } void MarbleWidgetPopupMenu::startReverseGeocoding() { const GeoDataCoordinates coordinates = d->mouseCoordinates( d->m_copyCoordinateAction ); if ( coordinates.isValid() ) { d->m_runnerManager.reverseGeocoding( coordinates ); } } void MarbleWidgetPopupMenu::showAddressInformation(const GeoDataCoordinates &, const GeoDataPlacemark &placemark) { QString text = placemark.address(); if ( !text.isEmpty() ) { QMessageBox::information( d->m_widget, tr( "Address Details" ), text, QMessageBox::Ok ); } } void MarbleWidgetPopupMenu::addBookmark() { const GeoDataCoordinates coordinates = d->mouseCoordinates( d->m_copyCoordinateAction ); if ( coordinates.isValid() ) { QPointer dialog = new EditBookmarkDialog( d->m_widget->model()->bookmarkManager(), d->m_widget ); dialog->setMarbleWidget( d->m_widget ); dialog->setCoordinates( coordinates ); dialog->setRange( d->m_widget->lookAt().range() ); dialog->setReverseGeocodeName(); if ( dialog->exec() == QDialog::Accepted ) { d->m_widget->model()->bookmarkManager()->addBookmark( dialog->folder(), dialog->bookmark() ); } delete dialog; } } void MarbleWidgetPopupMenu::toggleFullscreen( bool enabled ) { QWidget* parent = d->m_widget; for ( ; parent->parentWidget(); parent = parent->parentWidget() ) { // nothing to do } if ( enabled ) { parent->setWindowState( parent->windowState() | Qt::WindowFullScreen ); } else { parent->setWindowState( parent->windowState() & ~Qt::WindowFullScreen ); } } QPoint MarbleWidgetPopupMenu::mousePosition() const { return d->m_mousePosition; } } #include "moc_MarbleWidgetPopupMenu.cpp" diff --git a/src/lib/marble/PlacemarkLayout.cpp b/src/lib/marble/PlacemarkLayout.cpp index 0b728c7cf..ed2ef3d35 100644 --- a/src/lib/marble/PlacemarkLayout.cpp +++ b/src/lib/marble/PlacemarkLayout.cpp @@ -1,723 +1,721 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2006-2007 Torsten Rahn // Copyright 2007-2008 Inge Wallin // Copyright 2010-2012 Bernhard Beschow // #include "PlacemarkLayout.h" #include #include #include #include #include #include #include #include #include "GeoDataLatLonAltBox.h" #include "GeoDataPlacemark.h" #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include "GeoDataLabelStyle.h" -#include "GeoDataTypes.h" #include "OsmPlacemarkData.h" #include "MarbleDebug.h" #include "MarbleGlobal.h" #include "PlacemarkLayer.h" #include "MarbleClock.h" #include "MarblePlacemarkModel.h" #include "MarbleDirs.h" #include "ViewportParams.h" #include "TileId.h" #include "TileCoordsPyramid.h" #include "VisiblePlacemark.h" #include "MathHelper.h" #include namespace { //Helper function that checks for available room for the label bool hasRoomFor(const QVector & placemarks, const QRectF &boundingBox) { // Check if there is another label or symbol that overlaps. QVector::const_iterator beforeItEnd = placemarks.constEnd(); for ( QVector::ConstIterator beforeIt = placemarks.constBegin(); beforeIt != beforeItEnd; ++beforeIt ) { if ( boundingBox.intersects( (*beforeIt)->boundingBox() ) ) { return false; } } return true; } } namespace Marble { QSet acceptedVisualCategories() { QSet visualCategories; visualCategories << GeoDataPlacemark::SmallCity << GeoDataPlacemark::SmallCountyCapital << GeoDataPlacemark::SmallStateCapital << GeoDataPlacemark::SmallNationCapital << GeoDataPlacemark::MediumCity << GeoDataPlacemark::MediumCountyCapital << GeoDataPlacemark::MediumStateCapital << GeoDataPlacemark::MediumNationCapital << GeoDataPlacemark::BigCity << GeoDataPlacemark::BigCountyCapital << GeoDataPlacemark::BigStateCapital << GeoDataPlacemark::BigNationCapital << GeoDataPlacemark::LargeCity << GeoDataPlacemark::LargeCountyCapital << GeoDataPlacemark::LargeStateCapital << GeoDataPlacemark::LargeNationCapital << GeoDataPlacemark::Nation << GeoDataPlacemark::Mountain << GeoDataPlacemark::Volcano << GeoDataPlacemark::Mons << GeoDataPlacemark::Valley << GeoDataPlacemark::Continent << GeoDataPlacemark::Ocean << GeoDataPlacemark::OtherTerrain << GeoDataPlacemark::Crater << GeoDataPlacemark::Mare << GeoDataPlacemark::GeographicPole << GeoDataPlacemark::MagneticPole << GeoDataPlacemark::ShipWreck << GeoDataPlacemark::PlaceSuburb << GeoDataPlacemark::PlaceHamlet << GeoDataPlacemark::PlaceLocality; return visualCategories; } PlacemarkLayout::PlacemarkLayout( QAbstractItemModel *placemarkModel, QItemSelectionModel *selectionModel, MarbleClock *clock, const StyleBuilder *styleBuilder, QObject* parent ) : QObject( parent ), m_placemarkModel(placemarkModel), m_selectionModel( selectionModel ), m_clock( clock ), m_acceptedVisualCategories( acceptedVisualCategories() ), m_showPlaces( false ), m_showCities( false ), m_showTerrain( false ), m_showOtherPlaces( false ), m_showLandingSites( false ), m_showCraters( false ), m_showMaria( false ), m_maxLabelHeight(maxLabelHeight()), m_styleResetRequested( true ), m_styleBuilder(styleBuilder), m_lastPlacemarkAt(nullptr) { Q_ASSERT(m_placemarkModel); connect( m_selectionModel, SIGNAL( selectionChanged( QItemSelection, QItemSelection) ), this, SLOT(requestStyleReset()) ); connect( m_placemarkModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(resetCacheData()) ); connect( m_placemarkModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(addPlacemarks(QModelIndex,int,int)) ); connect( m_placemarkModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(removePlacemarks(QModelIndex,int,int)) ); connect( m_placemarkModel, SIGNAL(modelReset()), this, SLOT(resetCacheData()) ); } PlacemarkLayout::~PlacemarkLayout() { styleReset(); } void PlacemarkLayout::setShowPlaces( bool show ) { m_showPlaces = show; } void PlacemarkLayout::setShowCities( bool show ) { m_showCities = show; } void PlacemarkLayout::setShowTerrain( bool show ) { m_showTerrain = show; } void PlacemarkLayout::setShowOtherPlaces( bool show ) { m_showOtherPlaces = show; } void PlacemarkLayout::setShowLandingSites( bool show ) { m_showLandingSites = show; } void PlacemarkLayout::setShowCraters( bool show ) { m_showCraters = show; } void PlacemarkLayout::setShowMaria( bool show ) { m_showMaria = show; } void PlacemarkLayout::requestStyleReset() { mDebug() << "Style reset requested."; m_styleResetRequested = true; } void PlacemarkLayout::styleReset() { clearCache(); m_maxLabelHeight = maxLabelHeight(); m_styleResetRequested = false; } void PlacemarkLayout::clearCache() { m_paintOrder.clear(); m_lastPlacemarkAt = nullptr; m_labelArea = 0; qDeleteAll( m_visiblePlacemarks ); m_visiblePlacemarks.clear(); } QVector PlacemarkLayout::whichPlacemarkAt( const QPoint& curpos ) { if ( m_styleResetRequested ) { styleReset(); } QVector ret; for( VisiblePlacemark* mark: m_paintOrder ) { if ( mark->labelRect().contains( curpos ) || mark->symbolRect().contains( curpos ) ) { ret.append( mark->placemark() ); } } return ret; } int PlacemarkLayout::maxLabelHeight() const { QFont const standardFont(QStringLiteral("Sans Serif")); return QFontMetrics(standardFont).height(); } /// feed an internal QMap of placemarks with TileId as key when model changes void PlacemarkLayout::addPlacemarks( const QModelIndex& parent, int first, int last ) { Q_ASSERT( first < m_placemarkModel->rowCount() ); Q_ASSERT( last < m_placemarkModel->rowCount() ); for( int i=first; i<=last; ++i ) { QModelIndex index = m_placemarkModel->index( i, 0, parent ); Q_ASSERT( index.isValid() ); auto const object = qvariant_cast(index.data(MarblePlacemarkModel::ObjectPointerRole)); - if (object->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - const GeoDataPlacemark *placemark = static_cast(object); + if (const GeoDataPlacemark *placemark = geodata_cast(object)) { const GeoDataCoordinates coordinates = placemarkIconCoordinates( placemark ); if ( !coordinates.isValid() ) { continue; } if (placemark->hasOsmData()) { qint64 const osmId = placemark->osmData().id(); if (osmId > 0) { if (m_osmIds.contains(osmId)) { continue; // placemark is already shown } m_osmIds << osmId; } } int zoomLevel = placemark->zoomLevel(); TileId key = TileId::fromCoordinates( coordinates, zoomLevel ); m_placemarkCache[key].append( placemark ); } } emit repaintNeeded(); } void PlacemarkLayout::removePlacemarks( const QModelIndex& parent, int first, int last ) { Q_ASSERT( first < m_placemarkModel->rowCount() ); Q_ASSERT( last < m_placemarkModel->rowCount() ); for( int i=first; i<=last; ++i ) { QModelIndex index = m_placemarkModel->index( i, 0, parent ); Q_ASSERT( index.isValid() ); const GeoDataPlacemark *placemark = static_cast(qvariant_cast( index.data( MarblePlacemarkModel::ObjectPointerRole ) )); const GeoDataCoordinates coordinates = placemarkIconCoordinates( placemark ); if ( !coordinates.isValid() ) { continue; } int zoomLevel = placemark->zoomLevel(); TileId key = TileId::fromCoordinates( coordinates, zoomLevel ); delete m_visiblePlacemarks[placemark]; m_visiblePlacemarks.remove(placemark); m_placemarkCache[key].removeAll( placemark ); if (placemark->hasOsmData()) { qint64 const osmId = placemark->osmData().id(); if (osmId > 0) { m_osmIds.remove(osmId); } } } emit repaintNeeded(); } void PlacemarkLayout::resetCacheData() { const int rowCount = m_placemarkModel->rowCount(); m_osmIds.clear(); m_placemarkCache.clear(); qDeleteAll(m_visiblePlacemarks); m_visiblePlacemarks.clear(); requestStyleReset(); addPlacemarks( m_placemarkModel->index( 0, 0 ), 0, rowCount ); emit repaintNeeded(); } QSet PlacemarkLayout::visibleTiles( const ViewportParams *viewport, int zoomLevel ) const { /* * rely on m_placemarkCache to find the placemarks for the tiles which * matter. The top level tiles have the more popular placemarks, * the bottom level tiles have the smaller ones, and we only get the ones * matching our latLonAltBox. */ qreal north, south, east, west; viewport->viewLatLonAltBox().boundaries(north, south, east, west); QSet tileIdSet; QVector geoRects; if( west <= east ) { geoRects << QRectF(west, north, east - west, south - north); } else { geoRects << QRectF(west, north, M_PI - west, south - north); geoRects << QRectF(-M_PI, north, east + M_PI, south - north); } for( const QRectF &geoRect: geoRects ) { TileId key; QRect rect; key = TileId::fromCoordinates( GeoDataCoordinates(geoRect.left(), north, 0), zoomLevel); rect.setLeft( key.x() ); rect.setTop( key.y() ); key = TileId::fromCoordinates( GeoDataCoordinates(geoRect.right(), south, 0), zoomLevel); rect.setRight( key.x() ); rect.setBottom( key.y() ); TileCoordsPyramid pyramid(0, zoomLevel ); pyramid.setBottomLevelCoords( rect ); for ( int level = pyramid.topLevel(); level <= pyramid.bottomLevel(); ++level ) { QRect const coords = pyramid.coords( level ); int x1, y1, x2, y2; coords.getCoords( &x1, &y1, &x2, &y2 ); for ( int x = x1; x <= x2; ++x ) { for ( int y = y1; y <= y2; ++y ) { TileId const tileId( 0, level, x, y ); tileIdSet.insert(tileId); } } } } return tileIdSet; } QVector PlacemarkLayout::generateLayout( const ViewportParams *viewport, int tileLevel ) { m_runtimeTrace.clear(); if ( m_placemarkModel->rowCount() <= 0 ) { clearCache(); return QVector(); } if ( m_styleResetRequested ) { styleReset(); } if ( m_maxLabelHeight == 0 ) { clearCache(); return QVector(); } QList placemarkList; int currentMaxLabelHeight; do { currentMaxLabelHeight = m_maxLabelHeight; const int secnumber = viewport->height() / m_maxLabelHeight + 1; m_rowsection.clear(); m_rowsection.resize(secnumber); m_paintOrder.clear(); m_lastPlacemarkAt = nullptr; m_labelArea = 0; // First handle the selected placemarks as they have the highest priority. const QModelIndexList selectedIndexes = m_selectionModel->selection().indexes(); auto const viewLatLonAltBox = viewport->viewLatLonAltBox(); for ( int i = 0; i < selectedIndexes.count(); ++i ) { const QModelIndex index = selectedIndexes.at( i ); const GeoDataPlacemark *placemark = static_cast(qvariant_cast(index.data( MarblePlacemarkModel::ObjectPointerRole ) )); const GeoDataCoordinates coordinates = placemarkIconCoordinates( placemark ); if ( !coordinates.isValid() ) { continue; } qreal x = 0; qreal y = 0; if ( !viewLatLonAltBox.contains( coordinates ) || ! viewport->screenCoordinates( coordinates, x, y )) { continue; } if( layoutPlacemark( placemark, coordinates, x, y, true) ) { // Make sure not to draw more placemarks on the screen than // specified by placemarksOnScreenLimit(). if ( placemarksOnScreenLimit( viewport->size() ) ) break; } } // Now handle all other placemarks... const QItemSelection selection = m_selectionModel->selection(); placemarkList.clear(); for ( const TileId &tileId: visibleTiles( viewport, tileLevel ) ) { placemarkList += m_placemarkCache.value( tileId ); } std::sort(placemarkList.begin(), placemarkList.end(), GeoDataPlacemark::placemarkLayoutOrderCompare); for ( const GeoDataPlacemark *placemark: placemarkList ) { const GeoDataCoordinates coordinates = placemarkIconCoordinates( placemark ); if ( !coordinates.isValid() ) { continue; } int zoomLevel = placemark->zoomLevel(); if ( zoomLevel > 20 ) { break; } qreal x = 0; qreal y = 0; if ( !viewLatLonAltBox.contains( coordinates ) || ! viewport->screenCoordinates( coordinates, x, y )) { continue; } if ( !placemark->isGloballyVisible() ) { continue; } const GeoDataPlacemark::GeoDataVisualCategory visualCategory = placemark->visualCategory(); // Skip city marks if we're not showing cities. if ( !m_showCities && visualCategory >= GeoDataPlacemark::SmallCity && visualCategory <= GeoDataPlacemark::Nation ) continue; // Skip terrain marks if we're not showing terrain. if ( !m_showTerrain && visualCategory >= GeoDataPlacemark::Mountain && visualCategory <= GeoDataPlacemark::OtherTerrain ) continue; // Skip other places if we're not showing other places. if ( !m_showOtherPlaces && visualCategory >= GeoDataPlacemark::GeographicPole && visualCategory <= GeoDataPlacemark::Observatory ) continue; // Skip landing sites if we're not showing landing sites. if ( !m_showLandingSites && visualCategory >= GeoDataPlacemark::MannedLandingSite && visualCategory <= GeoDataPlacemark::UnmannedHardLandingSite ) continue; // Skip craters if we're not showing craters. if ( !m_showCraters && visualCategory == GeoDataPlacemark::Crater ) continue; // Skip maria if we're not showing maria. if ( !m_showMaria && visualCategory == GeoDataPlacemark::Mare ) continue; if ( !m_showPlaces && visualCategory >= GeoDataPlacemark::GeographicPole && visualCategory <= GeoDataPlacemark::Observatory ) continue; // We handled selected placemarks already, so we skip them here... // Assuming that only a small amount of places is selected // we check for the selected state after all other filters bool isSelected = false; for ( const QModelIndex &index: selection.indexes() ) { const GeoDataPlacemark *mark = static_cast(qvariant_cast(index.data( MarblePlacemarkModel::ObjectPointerRole ) )); if (mark == placemark ) { isSelected = true; break; } } if ( isSelected ) continue; if( layoutPlacemark( placemark, coordinates, x, y, isSelected ) ) { // Make sure not to draw more placemarks on the screen than // specified by placemarksOnScreenLimit(). if ( placemarksOnScreenLimit( viewport->size() ) ) break; } } if (m_visiblePlacemarks.size() > qMax(100, 4 * m_paintOrder.size())) { auto const extendedBox = viewLatLonAltBox.scaled(2.0, 2.0); QVector outdated; for (auto placemark: m_visiblePlacemarks) { if (!extendedBox.contains(placemark->coordinates())) { outdated << placemark; } } for (auto placemark: outdated) { delete m_visiblePlacemarks.take(placemark->placemark()); } } } while (currentMaxLabelHeight != m_maxLabelHeight); m_runtimeTrace = QStringLiteral("Placemarks: %1 Drawn: %2").arg(placemarkList.count()).arg(m_paintOrder.size()); return m_paintOrder; } QString PlacemarkLayout::runtimeTrace() const { return m_runtimeTrace; } QList PlacemarkLayout::visiblePlacemarks() const { return m_visiblePlacemarks.values(); } bool PlacemarkLayout::hasPlacemarkAt(const QPoint &pos) { if ( m_styleResetRequested ) { styleReset(); } if (m_lastPlacemarkAt && (m_lastPlacemarkAt->labelRect().contains(pos) || m_lastPlacemarkAt->symbolRect().contains(pos))) { return true; } for(VisiblePlacemark* mark: m_paintOrder) { if (mark->labelRect().contains(pos) || mark->symbolRect().contains(pos)) { m_lastPlacemarkAt = mark; return true; } } return false; } bool PlacemarkLayout::layoutPlacemark( const GeoDataPlacemark *placemark, const GeoDataCoordinates &coordinates, qreal x, qreal y, bool selected ) { // Find the corresponding visible placemark VisiblePlacemark *mark = m_visiblePlacemarks.value( placemark ); if ( !mark ) { // If there is no visible placemark yet for this index, // create a new one... StyleParameters parameters; // @todo: Set / adjust to tile level parameters.placemark = placemark; auto style = m_styleBuilder->createStyle(parameters); mark = new VisiblePlacemark(placemark, coordinates, style); m_visiblePlacemarks.insert( placemark, mark ); connect( mark, SIGNAL(updateNeeded()), this, SIGNAL(repaintNeeded()) ); } GeoDataStyle::ConstPtr style = mark->style(); // Choose Section QPointF hotSpot = mark->hotSpot(); mark->setSelected(selected); mark->setSymbolPosition(QPointF(x - hotSpot.x(), y - hotSpot.y())); // Find out whether the area around the placemark is covered already. // If there's not enough space free don't add a VisiblePlacemark here. const QString labelText = placemark->displayName(); QRectF labelRect; if (!labelText.isEmpty()) { labelRect = roomForLabel(style, x, y, labelText, mark); } if (labelRect.isEmpty() && mark->symbolPixmap().isNull()) { return false; } if (!mark->symbolPixmap().isNull() && !hasRoomForPixmap(y, mark)) { return false; } mark->setLabelRect( labelRect ); // Add the current placemark to the matching row and its // direct neighbors. int idx = y / m_maxLabelHeight; if ( idx - 1 >= 0 ) { m_rowsection[ idx - 1 ].append( mark ); } m_rowsection[ idx ].append( mark ); if ( idx + 1 < m_rowsection.size() ) { m_rowsection[ idx + 1 ].append( mark ); } m_paintOrder.append( mark ); QRectF const boundingBox = mark->boundingBox(); Q_ASSERT(!boundingBox.isEmpty()); m_labelArea += boundingBox.width() * boundingBox.height(); m_maxLabelHeight = qMax(m_maxLabelHeight, qCeil(boundingBox.height())); return true; } GeoDataCoordinates PlacemarkLayout::placemarkIconCoordinates( const GeoDataPlacemark *placemark ) const { GeoDataCoordinates coordinates = placemark->coordinate( m_clock->dateTime()); if (!m_acceptedVisualCategories.contains(placemark->visualCategory())) { StyleParameters parameters; parameters.placemark = placemark; auto style = m_styleBuilder->createStyle(parameters); if (style->iconStyle().scaledIcon().isNull()) { return GeoDataCoordinates(); } } return coordinates; } QRectF PlacemarkLayout::roomForLabel( const GeoDataStyle::ConstPtr &style, const qreal x, const qreal y, const QString &labelText, const VisiblePlacemark* placemark) const { QFont labelFont = style->labelStyle().scaledFont(); int textHeight = QFontMetrics( labelFont ).height(); int textWidth; if ( style->labelStyle().glow() ) { labelFont.setWeight( 75 ); // Needed to calculate the correct pixmap size; textWidth = ( QFontMetrics( labelFont ).width( labelText ) + qRound( 2 * s_labelOutlineWidth ) ); } else { textWidth = ( QFontMetrics( labelFont ).width( labelText ) ); } const QVector currentsec = m_rowsection.at( y / m_maxLabelHeight ); QRectF const symbolRect = placemark->symbolRect(); if ( style->labelStyle().alignment() == GeoDataLabelStyle::Corner ) { const int symbolWidth = style->iconStyle().scaledIcon().size().width(); // Check the four possible positions by going through all of them for( int i=0; i<4; ++i ) { const qreal xPos = ( i/2 == 0 ) ? x + symbolWidth / 2 + 1 : x - symbolWidth / 2 - 1 - textWidth; const qreal yPos = ( i%2 == 0 ) ? y : y - textHeight; const QRectF labelRect = QRectF( xPos, yPos, textWidth, textHeight ); if (hasRoomFor(currentsec, labelRect.united(symbolRect))) { // claim the place immediately if it hasn't been used yet return labelRect; } } } else if ( style->labelStyle().alignment() == GeoDataLabelStyle::Center ) { int const offsetY = style->iconStyle().scaledIcon().height() / 2.0; QRectF labelRect = QRectF( x - textWidth / 2, y - offsetY - textHeight, textWidth, textHeight ); if (hasRoomFor(currentsec, labelRect.united(symbolRect))) { // claim the place immediately if it hasn't been used yet return labelRect; } } else if (style->labelStyle().alignment() == GeoDataLabelStyle::Right) { const int symbolWidth = style->iconStyle().scaledIcon().width(); const qreal startY = y - textHeight/2; const qreal xPos = x + symbolWidth / 2 + 1; // Check up to seven vertical positions (center, +3, -3 from center) for(int i=0; i<7; ++i) { const qreal increase = (i/2) * (textHeight + 1); //intentional integer arithmetics const qreal direction = (i%2 == 0 ? 1 : -1); const qreal yPos = startY + increase*direction; const QRectF labelRect = QRectF(xPos, yPos, textWidth, textHeight); if (hasRoomFor(currentsec, labelRect.united(symbolRect))) { return labelRect; } } } // At this point there is no space left for the rectangle anymore. return QRectF(); } bool PlacemarkLayout::hasRoomForPixmap(const qreal y, const VisiblePlacemark *placemark) const { const QVector currentsec = m_rowsection.at(y / m_maxLabelHeight); return hasRoomFor(currentsec, placemark->symbolRect()); } bool PlacemarkLayout::placemarksOnScreenLimit( const QSize &screenSize ) const { int ratio = ( m_labelArea * 100 ) / ( screenSize.width() * screenSize.height() ); return ratio >= 40; } } #include "moc_PlacemarkLayout.cpp" diff --git a/src/lib/marble/PlaybackAnimatedUpdateItem.cpp b/src/lib/marble/PlaybackAnimatedUpdateItem.cpp index 33112b07b..778acc8b7 100644 --- a/src/lib/marble/PlaybackAnimatedUpdateItem.cpp +++ b/src/lib/marble/PlaybackAnimatedUpdateItem.cpp @@ -1,258 +1,255 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Sanjiban Bairagya // #include "PlaybackAnimatedUpdateItem.h" #include "GeoDataAnimatedUpdate.h" #include "GeoDataDocument.h" #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" #include "GeoDataCreate.h" #include "GeoDataUpdate.h" #include "GeoDataDelete.h" #include "GeoDataChange.h" +#include "GeoDataFolder.h" +#include "GeoDataGroundOverlay.h" +#include "GeoDataPhotoOverlay.h" +#include "GeoDataScreenOverlay.h" #include namespace Marble { PlaybackAnimatedUpdateItem::PlaybackAnimatedUpdateItem( GeoDataAnimatedUpdate* animatedUpdate ) { m_animatedUpdate = animatedUpdate; m_rootDocument = rootDocument( m_animatedUpdate ); m_playing = false; } const GeoDataAnimatedUpdate* PlaybackAnimatedUpdateItem::animatedUpdate() const { return m_animatedUpdate; } double PlaybackAnimatedUpdateItem::duration() const { return m_animatedUpdate->duration(); } void PlaybackAnimatedUpdateItem::play() { if( m_playing ){ return; } m_playing = true; if ( !m_rootDocument || !m_animatedUpdate->update() ) { return; } // Apply updates of elements if ( m_animatedUpdate->update()->change() ) { QVector placemarkList = m_animatedUpdate->update()->change()->placemarkList(); for( int i = 0; i < placemarkList.size(); i++ ){ GeoDataPlacemark* placemark = placemarkList.at( i ); QString targetId = placemark->targetId(); if( targetId.isEmpty() ) { continue; } if( placemark->isBalloonVisible() ){ GeoDataFeature* feature = findFeature( m_rootDocument, targetId ); - if( feature && feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType ){ - emit balloonShown( static_cast( feature ) ); + if (auto placemark = geodata_cast(feature)) { + emit balloonShown(placemark); } } else { emit balloonHidden(); } } } // Create new elements if( m_animatedUpdate->update()->create() ){ for( int index = 0; index < m_animatedUpdate->update()->create()->size(); ++index ) { GeoDataFeature* child = m_animatedUpdate->update()->create()->child( index ); if( child && - ( child->nodeType() == GeoDataTypes::GeoDataDocumentType || - child->nodeType() == GeoDataTypes::GeoDataFolderType ) ) { + (geodata_cast(child)|| + geodata_cast(child))) { GeoDataContainer *addContainer = static_cast( child ); QString targetId = addContainer->targetId(); GeoDataFeature* feature = findFeature( m_rootDocument, targetId ); if( feature && - ( feature->nodeType() == GeoDataTypes::GeoDataDocumentType || - feature->nodeType() == GeoDataTypes::GeoDataFolderType ) ) { + (geodata_cast(feature) || + geodata_cast(feature))) { GeoDataContainer* container = static_cast( feature ); for( int i = 0; i < addContainer->size(); ++i ) { emit added( container, addContainer->child( i ), -1 ); - if( addContainer->child( i )->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) + if (auto placemark = geodata_cast(addContainer->child(i))) { - GeoDataPlacemark *placemark = static_cast( addContainer->child( i ) ); if( placemark->isBalloonVisible() ) { emit balloonShown( placemark ); } } } } } } } // Delete elements if( m_animatedUpdate->update()->getDelete() ){ for( int index = 0; index < m_animatedUpdate->update()->getDelete()->size(); ++index ) { GeoDataFeature* child = m_animatedUpdate->update()->getDelete()->child( index ); QString targetId = child->targetId(); if( targetId.isEmpty() ) { continue; } GeoDataFeature* feature = findFeature( m_rootDocument, targetId ); if (feature && canDelete(*feature)) { m_deletedObjects.append( feature ); emit removed( feature ); - if( feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) + if (auto placemark = geodata_cast(feature)) { - GeoDataPlacemark *placemark = static_cast( feature ); if( placemark->isBalloonVisible() ) { emit balloonHidden(); } } } } } } GeoDataFeature* PlaybackAnimatedUpdateItem::findFeature(GeoDataFeature* feature, const QString& id ) const { if ( feature && feature->id() == id ){ return feature; } GeoDataContainer *container = dynamic_cast( feature ); if ( container ){ QVector::Iterator end = container->end(); QVector::Iterator iter = container->begin(); for( ; iter != end; ++iter ){ GeoDataFeature *foundFeature = findFeature( *iter, id ); if ( foundFeature ){ return foundFeature; } } } return 0; } GeoDataDocument *PlaybackAnimatedUpdateItem::rootDocument( GeoDataObject* object ) const { if( !object || !object->parent() ){ GeoDataDocument* document = dynamic_cast( object ); return document; } else { return rootDocument( object->parent() ); } return 0; } void PlaybackAnimatedUpdateItem::pause() { //do nothing } void PlaybackAnimatedUpdateItem::seek( double position ) { Q_UNUSED( position ); play(); } void PlaybackAnimatedUpdateItem::stop() { if( !m_playing ){ return; } m_playing = false; if ( m_animatedUpdate->update()->change() ) { QVector placemarkList = m_animatedUpdate->update()->change()->placemarkList(); for( int i = 0; i < placemarkList.size(); i++ ){ GeoDataPlacemark* placemark = placemarkList.at( i ); QString targetId = placemark->targetId(); if( targetId.isEmpty() ) { continue; } GeoDataFeature* feature = findFeature( m_rootDocument, targetId ); if( placemark->isBalloonVisible() ){ - if( feature && feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType ){ + if (geodata_cast(feature)) { emit balloonHidden(); } } else { emit balloonShown( static_cast( feature ) ); } } } if( m_animatedUpdate->update()->create() ){ for( int index = 0; index < m_animatedUpdate->update()->create()->size(); ++index ) { GeoDataFeature* feature = m_animatedUpdate->update()->create()->child( index ); if( feature && - ( feature->nodeType() == GeoDataTypes::GeoDataDocumentType || - feature->nodeType() == GeoDataTypes::GeoDataFolderType ) ) { + (geodata_cast(feature) || + geodata_cast(feature))) { GeoDataContainer* container = static_cast( feature ); for( int i = 0; i < container->size(); ++i ) { emit removed( container->child( i ) ); - if( container->child( i )->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) + if (auto placemark = geodata_cast(container->child(i))) { - GeoDataPlacemark *placemark = static_cast( container->child( i ) ); if( placemark->isBalloonVisible() ) { emit balloonHidden(); } } } } } } for( GeoDataFeature* feature: m_deletedObjects ) { if( feature->targetId().isEmpty() ) { continue; } GeoDataFeature* target = findFeature( m_rootDocument, feature->targetId() ); if ( target ) { /** @todo Do we have to note the original row position and restore it? */ Q_ASSERT( dynamic_cast( target ) ); emit added( static_cast( target ), feature, -1 ); - if( feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) + if (auto placemark = geodata_cast(feature)) { - GeoDataPlacemark *placemark = static_cast( feature ); if( placemark->isBalloonVisible() ) { emit balloonShown( placemark ); } } } // else the root document was modified in an unfortunate way and we cannot restore it at this point } m_deletedObjects.clear(); } bool PlaybackAnimatedUpdateItem::isApplied() const { return m_playing; } bool PlaybackAnimatedUpdateItem::canDelete(const GeoDataFeature &feature) { - const char *nodeType = feature.nodeType(); - - return nodeType == GeoDataTypes::GeoDataDocumentType || - nodeType == GeoDataTypes::GeoDataFolderType || - nodeType == GeoDataTypes::GeoDataGroundOverlayType || - nodeType == GeoDataTypes::GeoDataPlacemarkType || - nodeType == GeoDataTypes::GeoDataScreenOverlayType || - nodeType == GeoDataTypes::GeoDataPhotoOverlayType; + return geodata_cast(&feature) || + geodata_cast(&feature) || + geodata_cast(&feature) || + geodata_cast(&feature) || + geodata_cast(&feature) || + geodata_cast(&feature); } } #include "moc_PlaybackAnimatedUpdateItem.cpp" diff --git a/src/lib/marble/PlaybackFlyToItem.cpp b/src/lib/marble/PlaybackFlyToItem.cpp index 9309e9032..052aad621 100644 --- a/src/lib/marble/PlaybackFlyToItem.cpp +++ b/src/lib/marble/PlaybackFlyToItem.cpp @@ -1,136 +1,135 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Sanjiban Bairagya // #include "PlaybackFlyToItem.h" -#include "GeoDataTypes.h" #include "GeoDataLookAt.h" #include "GeoDataCamera.h" #include "GeoDataFlyTo.h" #include "Quaternion.h" #include namespace Marble { PlaybackFlyToItem::PlaybackFlyToItem( const GeoDataFlyTo* flyTo ): m_flyTo( flyTo ), m_before( 0 ), m_next( 0 ), m_isPlaying( false ), m_isFirst( false ) { //do nothing } const GeoDataFlyTo* PlaybackFlyToItem::flyTo() const { return m_flyTo; } double PlaybackFlyToItem::duration() const { // We use duration 0 for first FlyTo for instantly flight to it. return m_isFirst ? 0 : m_flyTo->duration(); } void PlaybackFlyToItem::play() { if( m_isPlaying ){ return; } else { m_isPlaying = true; if ( !( m_start.isValid() ) ){ m_start = QDateTime::currentDateTime(); Q_ASSERT( m_start.isValid() ); } else { m_start = m_start.addMSecs( m_pause.msecsTo( QDateTime::currentDateTime() ) ); } playNext(); } } void PlaybackFlyToItem::playNext() { if( !m_start.isValid() ){ return; } double const progress = m_start.msecsTo( QDateTime::currentDateTime() ) / 1000.0; Q_ASSERT( progress >= 0.0 ); double const t = progress / duration(); if( t <= 1 ){ if( m_isPlaying ){ center( t ); emit progressChanged( progress ); QTimer::singleShot( 5, this, SLOT(playNext()) ); } } else { center( 1.0 ); emit finished(); stop(); } } void PlaybackFlyToItem::pause() { m_isPlaying = false; m_pause = QDateTime::currentDateTime(); } void PlaybackFlyToItem::seek( double t ) { m_start = QDateTime::currentDateTime().addMSecs( -t * duration() * 1000 ); m_pause = QDateTime::currentDateTime(); center( t ); } void PlaybackFlyToItem::stop() { m_isPlaying = false; m_start = QDateTime(); m_pause = QDateTime(); } void PlaybackFlyToItem::center( double t ) { Q_ASSERT( t >= 0.0 && t <= 1.0 ); Q_ASSERT( m_before ); if ( m_flyTo->flyToMode() == GeoDataFlyTo::Bounce || !m_before->m_before || !m_next ) { GeoDataCoordinates const a = m_before->m_flyTo->view()->coordinates(); GeoDataCoordinates const b = m_flyTo->view()->coordinates(); emit centerOn( a.interpolate( b, t ) ); } else { Q_ASSERT( m_flyTo->flyToMode() == GeoDataFlyTo::Smooth ); GeoDataCoordinates const a = m_before->m_before->m_flyTo->view()->coordinates(); GeoDataCoordinates const b = m_before->m_flyTo->view()->coordinates(); GeoDataCoordinates const c = m_flyTo->view()->coordinates(); GeoDataCoordinates const d = m_next->m_flyTo->view()->coordinates(); emit centerOn( b.interpolate( a, c, d, t ) ); } } void PlaybackFlyToItem::setBefore( PlaybackFlyToItem *before ) { m_before = before; } void PlaybackFlyToItem::setNext( PlaybackFlyToItem *next ) { m_next = next; } void PlaybackFlyToItem::setFirst(bool isFirst) { m_isFirst = isFirst; } } #include "moc_PlaybackFlyToItem.cpp" diff --git a/src/lib/marble/PositionTracking.cpp b/src/lib/marble/PositionTracking.cpp index 97deff5be..60c9f59a6 100644 --- a/src/lib/marble/PositionTracking.cpp +++ b/src/lib/marble/PositionTracking.cpp @@ -1,400 +1,399 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2007 Andrew Manson // Copyright 2009 Eckhart Wörner // Copyright 2010 Thibaut Gridel // #include "PositionTracking.h" #include "GeoDataDocument.h" #include "GeoDataMultiTrack.h" #include "GeoDataPlacemark.h" #include "GeoDataParser.h" #include "GeoDataStyle.h" #include "GeoDataLineStyle.h" #include "GeoDataStyleMap.h" #include "GeoDataTrack.h" #include "GeoDataTreeModel.h" -#include "GeoDataTypes.h" #include "GeoDataLineString.h" #include "GeoDataAccuracy.h" #include "GeoDataDocumentWriter.h" #include "KmlElementDictionary.h" #include "FileManager.h" #include "MarbleMath.h" #include "MarbleDebug.h" #include "MarbleDirs.h" #include "PositionProviderPlugin.h" #include namespace Marble { class PositionTrackingPrivate { public: PositionTrackingPrivate( GeoDataTreeModel *model, PositionTracking *parent ) : q( parent ), m_treeModel( model ), m_currentPositionPlacemark( new GeoDataPlacemark ), m_currentTrackPlacemark( new GeoDataPlacemark ), m_trackSegments( new GeoDataMultiTrack ), m_document(), m_currentTrack( 0 ), m_positionProvider( 0 ), m_length( 0.0 ) { } void updatePosition(); void updateStatus(); static QString statusFile(); PositionTracking *const q; GeoDataTreeModel *const m_treeModel; GeoDataPlacemark *const m_currentPositionPlacemark; GeoDataPlacemark *m_currentTrackPlacemark; GeoDataMultiTrack *m_trackSegments; GeoDataDocument m_document; GeoDataCoordinates m_gpsPreviousPosition; GeoDataTrack *m_currentTrack; PositionProviderPlugin* m_positionProvider; qreal m_length; }; void PositionTrackingPrivate::updatePosition() { Q_ASSERT( m_positionProvider != 0 ); const GeoDataAccuracy accuracy = m_positionProvider->accuracy(); const GeoDataCoordinates position = m_positionProvider->position(); const QDateTime timestamp = m_positionProvider->timestamp(); if ( m_positionProvider->status() == PositionProviderStatusAvailable ) { if ( accuracy.horizontal < 250 ) { if ( m_currentTrack->size() ) { m_length += distanceSphere( m_currentTrack->coordinatesAt( m_currentTrack->size() - 1 ), position ); } m_currentTrack->addPoint( timestamp, position ); } //if the position has moved then update the current position if ( m_gpsPreviousPosition != position ) { m_currentPositionPlacemark->setCoordinate( position ); qreal speed = m_positionProvider->speed(); emit q->gpsLocation( position, speed ); } } } void PositionTrackingPrivate::updateStatus() { Q_ASSERT( m_positionProvider != 0 ); const PositionProviderStatus status = m_positionProvider->status(); if (status == PositionProviderStatusAvailable) { m_currentTrack = new GeoDataTrack; m_treeModel->removeFeature( m_currentTrackPlacemark ); m_trackSegments->append( m_currentTrack ); m_treeModel->addFeature( &m_document, m_currentTrackPlacemark ); } emit q->statusChanged( status ); } QString PositionTrackingPrivate::statusFile() { QString const subdir = "tracking"; QDir dir( MarbleDirs::localPath() ); if ( !dir.exists( subdir ) ) { if ( !dir.mkdir( subdir ) ) { mDebug() << "Unable to create dir " << dir.absoluteFilePath( subdir ); return dir.absolutePath(); } } if ( !dir.cd( subdir ) ) { mDebug() << "Cannot change into " << dir.absoluteFilePath( subdir ); } return dir.absoluteFilePath( "track.kml" ); } PositionTracking::PositionTracking( GeoDataTreeModel *model ) : QObject( model ), d( new PositionTrackingPrivate( model, this ) ) { d->m_document.setDocumentRole( TrackingDocument ); d->m_document.setName(QStringLiteral("Position Tracking")); // First point is current position d->m_currentPositionPlacemark->setName(QStringLiteral("Current Position")); d->m_currentPositionPlacemark->setVisible(false); d->m_document.append( d->m_currentPositionPlacemark ); // Second point is position track d->m_currentTrack = new GeoDataTrack; d->m_trackSegments->append(d->m_currentTrack); d->m_currentTrackPlacemark->setGeometry(d->m_trackSegments); d->m_currentTrackPlacemark->setName(QStringLiteral("Current Track")); GeoDataStyle::Ptr style(new GeoDataStyle); GeoDataLineStyle lineStyle; QColor transparentRed = Oxygen::brickRed4; transparentRed.setAlpha( 200 ); lineStyle.setColor( transparentRed ); lineStyle.setWidth( 4 ); style->setLineStyle(lineStyle); style->setId(QStringLiteral("track")); GeoDataStyleMap styleMap; styleMap.setId(QStringLiteral("map-track")); styleMap.insert(QStringLiteral("normal"), QLatin1Char('#') + style->id()); d->m_document.addStyleMap(styleMap); d->m_document.addStyle(style); d->m_document.append( d->m_currentTrackPlacemark ); d->m_currentTrackPlacemark->setStyleUrl(QLatin1Char('#') + styleMap.id()); d->m_treeModel->addDocument( &d->m_document ); } PositionTracking::~PositionTracking() { d->m_treeModel->removeDocument( &d->m_document ); delete d; } void PositionTracking::setPositionProviderPlugin( PositionProviderPlugin* plugin ) { const PositionProviderStatus oldStatus = status(); if ( d->m_positionProvider ) { delete d->m_positionProvider; } d->m_positionProvider = plugin; if ( d->m_positionProvider ) { d->m_positionProvider->setParent( this ); mDebug() << "Initializing position provider:" << d->m_positionProvider->name(); connect( d->m_positionProvider, SIGNAL(statusChanged(PositionProviderStatus)), this, SLOT(updateStatus()) ); connect( d->m_positionProvider, SIGNAL(positionChanged(GeoDataCoordinates,GeoDataAccuracy)), this, SLOT(updatePosition()) ); d->m_positionProvider->initialize(); } emit positionProviderPluginChanged( plugin ); if ( oldStatus != status() ) { emit statusChanged( status() ); } if ( status() == PositionProviderStatusAvailable ) { emit gpsLocation( d->m_positionProvider->position(), d->m_positionProvider->speed() ); } } PositionProviderPlugin* PositionTracking::positionProviderPlugin() { return d->m_positionProvider; } QString PositionTracking::error() const { return d->m_positionProvider ? d->m_positionProvider->error() : QString(); } //get speed from provider qreal PositionTracking::speed() const { return d->m_positionProvider ? d->m_positionProvider->speed() : 0 ; } //get direction from provider qreal PositionTracking::direction() const { return d->m_positionProvider ? d->m_positionProvider->direction() : 0 ; } QDateTime PositionTracking::timestamp() const { return d->m_positionProvider ? d->m_positionProvider->timestamp() : QDateTime(); } bool PositionTracking::trackVisible() const { return d->m_currentTrackPlacemark->isVisible(); } void PositionTracking::setTrackVisible( bool visible ) { d->m_currentTrackPlacemark->setVisible( visible ); d->m_treeModel->updateFeature( d->m_currentTrackPlacemark ); } bool PositionTracking::saveTrack( const QString& fileName ) { if ( fileName.isEmpty() ) { return false; } GeoDataDocument *document = new GeoDataDocument; QFileInfo fileInfo( fileName ); QString name = fileInfo.baseName(); document->setName( name ); for( const GeoDataStyle::Ptr &style: d->m_document.styles() ) { document->addStyle( style ); } for( const GeoDataStyleMap &map: d->m_document.styleMaps() ) { document->addStyleMap( map ); } GeoDataPlacemark *track = new GeoDataPlacemark( *d->m_currentTrackPlacemark ); track->setName(QLatin1String("Track ") + name); document->append( track ); bool const result = GeoDataDocumentWriter::write(fileName, *document); delete document; return result; } void PositionTracking::clearTrack() { d->m_treeModel->removeFeature( d->m_currentTrackPlacemark ); d->m_currentTrack = new GeoDataTrack; d->m_trackSegments->clear(); d->m_trackSegments->append( d->m_currentTrack ); d->m_treeModel->addFeature( &d->m_document, d->m_currentTrackPlacemark ); d->m_length = 0.0; } void PositionTracking::readSettings() { QFile file( d->statusFile() ); if ( !file.open( QIODevice::ReadOnly ) ) { mDebug() << "Can not read track from " << file.fileName(); return; } GeoDataParser parser( GeoData_KML ); if ( !parser.read( &file ) ) { mDebug() << "Could not parse tracking file: " << parser.errorString(); return; } GeoDataDocument *doc = dynamic_cast( parser.releaseDocument() ); file.close(); if( !doc ){ mDebug() << "tracking document not available"; return; } GeoDataPlacemark *track = dynamic_cast( doc->child( 0 ) ); if( !track ) { mDebug() << "tracking document doesn't have a placemark"; delete doc; return; } d->m_trackSegments = dynamic_cast( track->geometry() ); if( !d->m_trackSegments ) { mDebug() << "tracking document doesn't have a multitrack"; delete doc; return; } if( d->m_trackSegments->size() < 1 ) { mDebug() << "tracking document doesn't have a track"; delete doc; return; } d->m_currentTrack = dynamic_cast( d->m_trackSegments->child( d->m_trackSegments->size() - 1 ) ); if( !d->m_currentTrack ) { mDebug() << "tracking document doesn't have a last track"; delete doc; return; } doc->remove( 0 ); delete doc; d->m_treeModel->removeDocument( &d->m_document ); d->m_document.remove( 1 ); delete d->m_currentTrackPlacemark; d->m_currentTrackPlacemark = track; d->m_currentTrackPlacemark->setName(QStringLiteral("Current Track")); d->m_document.append( d->m_currentTrackPlacemark ); d->m_currentTrackPlacemark->setStyleUrl( d->m_currentTrackPlacemark->styleUrl() ); d->m_treeModel->addDocument( &d->m_document ); d->m_length = 0.0; for ( int i = 0; i < d->m_trackSegments->size(); ++i ) { d->m_length += d->m_trackSegments->at( i ).lineString()->length( 1 ); } } void PositionTracking::writeSettings() { saveTrack( d->statusFile() ); } bool PositionTracking::isTrackEmpty() const { if ( d->m_trackSegments->size() < 1 ) { return true; } if ( d->m_trackSegments->size() == 1 ) { return ( d->m_currentTrack->size() == 0 ); } return false; } qreal PositionTracking::length( qreal planetRadius ) const { return d->m_length * planetRadius; } GeoDataAccuracy PositionTracking::accuracy() const { return d->m_positionProvider ? d->m_positionProvider->accuracy() : GeoDataAccuracy(); } GeoDataCoordinates PositionTracking::currentLocation() const { return d->m_positionProvider ? d->m_positionProvider->position() : GeoDataCoordinates(); } PositionProviderStatus PositionTracking::status() const { return d->m_positionProvider ? d->m_positionProvider->status() : PositionProviderStatusUnavailable; } } #include "moc_PositionTracking.cpp" diff --git a/src/lib/marble/RemoveItemEditWidget.cpp b/src/lib/marble/RemoveItemEditWidget.cpp index e4e3bf427..f5944a142 100644 --- a/src/lib/marble/RemoveItemEditWidget.cpp +++ b/src/lib/marble/RemoveItemEditWidget.cpp @@ -1,94 +1,94 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Mihail Ivchenko // #include #include #include #include #include "RemoveItemEditWidget.h" #include "MarbleWidget.h" #include "geodata/data/GeoDataAnimatedUpdate.h" -#include "GeoDataTypes.h" #include "GeoDataUpdate.h" #include "GeoDataDelete.h" #include "MarblePlacemarkModel.h" namespace Marble { RemoveItemEditWidget::RemoveItemEditWidget( const QModelIndex &index, QWidget *parent ) : QWidget( parent ), m_index( index ), m_button( new QToolButton ), m_comboBox( new QComboBox ) { QHBoxLayout *layout = new QHBoxLayout; layout->setSpacing( 5 ); QLabel* iconLabel = new QLabel; iconLabel->setPixmap(QPixmap(QStringLiteral(":/icons/remove.png"))); layout->addWidget( iconLabel ); QLabel* comboBoxLabel = new QLabel; comboBoxLabel->setText( tr( "Choose item:" ) ); layout->addWidget( comboBoxLabel ); layout->addWidget( m_comboBox ); m_button->setIcon(QIcon(QStringLiteral(":/marble/document-save.png"))); connect(m_button, SIGNAL(clicked()), this, SLOT(save())); layout->addWidget( m_button ); setLayout( layout ); } bool RemoveItemEditWidget::editable() const { return m_button->isEnabled(); } void RemoveItemEditWidget::setFeatureIds( const QStringList &ids ) { QString id = animatedUpdateElement()->update()->getDelete()->first().targetId(); QString current = m_comboBox->currentIndex() == -1 ? id : m_comboBox->currentText(); m_comboBox->clear(); m_comboBox->addItems( ids ); m_comboBox->setCurrentIndex( m_comboBox->findText( current ) ); } void RemoveItemEditWidget::setDefaultFeatureId( const QString &featureId ) { if( m_comboBox->currentIndex() == -1 ) { m_comboBox->setCurrentIndex( m_comboBox->findText( featureId ) ); } } void RemoveItemEditWidget::setEditable( bool editable ) { m_button->setEnabled( editable ); } void RemoveItemEditWidget::save() { animatedUpdateElement()->update()->getDelete()->child(0)->setTargetId( m_comboBox->currentText() ); emit editingDone(m_index); } GeoDataAnimatedUpdate* RemoveItemEditWidget::animatedUpdateElement() { GeoDataObject *object = qvariant_cast(m_index.data( MarblePlacemarkModel::ObjectPointerRole ) ); Q_ASSERT( object ); - Q_ASSERT( object->nodeType() == GeoDataTypes::GeoDataAnimatedUpdateType ); - return static_cast( object ); + auto animatedUpdate = geodata_cast(object); + Q_ASSERT(animatedUpdate); + return animatedUpdate; } } // namespace Marble #include "moc_RemoveItemEditWidget.cpp" diff --git a/src/lib/marble/SerialTrack.cpp b/src/lib/marble/SerialTrack.cpp index ba5586cc7..d40b09e0d 100644 --- a/src/lib/marble/SerialTrack.cpp +++ b/src/lib/marble/SerialTrack.cpp @@ -1,178 +1,177 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Sanjiban Bairagya // #include "SerialTrack.h" -#include "GeoDataTypes.h" #include "PlaybackFlyToItem.h" #include "PlaybackWaitItem.h" #include "PlaybackTourControlItem.h" #include "GeoDataCamera.h" #include "GeoDataLookAt.h" #include "TourPlayback.h" namespace Marble { SerialTrack::SerialTrack(): QObject() { m_currentIndex = 0; m_finishedPosition = 0; m_currentPosition = 0; m_paused = true; } SerialTrack::~SerialTrack() { clear(); } void SerialTrack::append(PlaybackItem* item) { connect( item, SIGNAL(progressChanged(double)), this, SLOT(changeProgress(double)) ); connect( item, SIGNAL(centerOn(GeoDataCoordinates)), this, SIGNAL(centerOn(GeoDataCoordinates)) ); connect( item, SIGNAL(finished()), this, SLOT(handleFinishedItem()) ) ; connect( item, SIGNAL(paused()), this, SLOT(pause()) ) ; m_items.append( item ); if( m_items.size() == 1 ) { PlaybackFlyToItem *flyTo = dynamic_cast( item ); if( flyTo != 0 ) { flyTo->setFirst( true ) ; } } } void SerialTrack::play() { m_paused = false; m_items[m_currentIndex]->play(); } void SerialTrack::pause() { m_paused = true; m_items[m_currentIndex]->pause(); } void SerialTrack::stop() { m_paused = true; if( m_items.size() != 0 && m_currentIndex >= 0 && m_currentIndex <= m_items.size() - 1 ){ m_items[m_currentIndex]->stop(); } m_finishedPosition = 0; emit progressChanged( m_finishedPosition ); m_currentIndex = 0; } void SerialTrack::seek( double offset ) { m_currentPosition = offset; int index = -1; for( int i = 0; i < m_items.size(); i++ ){ if( offset < m_items[i]->duration() ){ index = i; break; } else { m_items[i]->stop(); offset -= m_items[i]->duration(); } } if( index == -1 ){ index = m_items.size() - 1; } if( index < m_items.size() - 1 ){ for( int i = index + 1; i < m_items.size(); i++ ){ m_items[ i ]->stop(); } } if( index > m_currentIndex ){ for( int i = m_currentIndex; i < index ; i++ ){ m_finishedPosition += m_items[ i ]->duration(); } }else{ for( int i = m_currentIndex - 1; i >= index && i >= 0; i-- ){ m_finishedPosition -= m_items[ i ]->duration(); } } if (m_currentIndex != index && !m_paused) { m_items[ index ]->play(); } m_currentIndex = index; if ( m_currentIndex != -1 ){ double t = offset / m_items[ m_currentIndex ]->duration(); Q_ASSERT( t >= 0 && t <= 1 ); m_items[ m_currentIndex ]->seek( t ); } } double SerialTrack::duration() const { double duration = 0.0; for (PlaybackItem* item: m_items) { duration += item->duration(); } return duration; } void SerialTrack::clear() { qDeleteAll( m_items ); m_items.clear(); m_currentIndex = 0; m_finishedPosition = 0; m_currentPosition = 0; m_paused = true; } void SerialTrack::handleFinishedItem() { if( m_paused ){ return; } if ( m_currentIndex + 1 < m_items.size() ) { m_finishedPosition += m_items[m_currentIndex]->duration(); m_currentIndex++; m_items[m_currentIndex]->play(); emit itemFinished( m_currentIndex + 1 ); } else { emit finished(); } } void SerialTrack::changeProgress( double progress ) { m_currentPosition = m_finishedPosition + progress; emit progressChanged( m_currentPosition ); } int SerialTrack::size() const { return m_items.size(); } PlaybackItem* SerialTrack::at( int i ) { return m_items.at( i ); } double SerialTrack::currentPosition() { return m_currentPosition; } } #include "moc_SerialTrack.cpp" diff --git a/src/lib/marble/SoundCueEditWidget.cpp b/src/lib/marble/SoundCueEditWidget.cpp index f12d6740c..0dd5433c4 100644 --- a/src/lib/marble/SoundCueEditWidget.cpp +++ b/src/lib/marble/SoundCueEditWidget.cpp @@ -1,88 +1,88 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2013 Mihail Ivchenko // Copyright 2014 Sanjiban Bairagya // Copyright 2014 Illya Kovalevskyy // #include #include #include #include #include #include "SoundCueEditWidget.h" #include "MarbleWidget.h" #include "geodata/data/GeoDataSoundCue.h" -#include "GeoDataTypes.h" #include "MarblePlacemarkModel.h" namespace Marble { SoundCueEditWidget::SoundCueEditWidget( const QModelIndex &index, QWidget *parent ) : QWidget( parent ), m_index( index ), m_lineEdit( new QLineEdit ), m_button( new QToolButton ), m_button2( new QToolButton ) { QHBoxLayout *layout = new QHBoxLayout; layout->setSpacing( 5 ); QLabel* iconLabel = new QLabel; iconLabel->setPixmap(QPixmap(QStringLiteral(":/marble/playback-play.png"))); layout->addWidget( iconLabel ); m_lineEdit->setPlaceholderText( "Audio location" ); m_lineEdit->setText( soundCueElement()->href() ); layout->addWidget( m_lineEdit ); m_button2->setIcon(QIcon(QStringLiteral(":/marble/document-open.png"))); connect(m_button2, SIGNAL(clicked()), this, SLOT(open())); layout->addWidget( m_button2 ); m_button->setIcon(QIcon(QStringLiteral(":/marble/document-save.png"))); connect(m_button, SIGNAL(clicked()), this, SLOT(save())); layout->addWidget( m_button ); setLayout( layout ); } bool SoundCueEditWidget::editable() const { return m_button->isEnabled(); } void SoundCueEditWidget::setEditable( bool editable ) { m_button->setEnabled( editable ); } void SoundCueEditWidget::save() { soundCueElement()->setHref( m_lineEdit->text() ); emit editingDone(m_index); } void SoundCueEditWidget::open() { QString fileName = QFileDialog::getOpenFileName(this, tr("Select sound files..."), QDir::homePath(), tr("Supported Sound Files (*.mp3 *.ogg *.wav)")); m_lineEdit->setText(fileName); soundCueElement()->setHref( m_lineEdit->text() ); } GeoDataSoundCue* SoundCueEditWidget::soundCueElement() { GeoDataObject *object = qvariant_cast(m_index.data( MarblePlacemarkModel::ObjectPointerRole ) ); Q_ASSERT( object ); - Q_ASSERT( object->nodeType() == GeoDataTypes::GeoDataSoundCueType ); - return static_cast( object ); + auto soundCue = geodata_cast(object); + Q_ASSERT(soundCue); + return soundCue; } } // namespace Marble #include "moc_SoundCueEditWidget.cpp" diff --git a/src/lib/marble/StyleBuilder.cpp b/src/lib/marble/StyleBuilder.cpp index 80892f3dc..602f746f4 100644 --- a/src/lib/marble/StyleBuilder.cpp +++ b/src/lib/marble/StyleBuilder.cpp @@ -1,3010 +1,3013 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2007 Murad Tagirov // Copyright 2009 Patrick Spendrin // Copyright 2015 Marius-Valeriu Stanciu // Copyright 2016 Dennis Nienhüser // #include "StyleBuilder.h" #include "MarbleDirs.h" #include "OsmPlacemarkData.h" #include "OsmcSymbol.h" -#include "GeoDataTypes.h" #include "GeoDataGeometry.h" +#include "GeoDataLinearRing.h" +#include "GeoDataLineString.h" #include "GeoDataPlacemark.h" +#include "GeoDataPoint.h" +#include "GeoDataPolygon.h" #include "GeoDataIconStyle.h" #include "GeoDataLabelStyle.h" #include "GeoDataLineStyle.h" #include "GeoDataPolyStyle.h" #include #include #include #include #include #include #include #include namespace Marble { class StyleBuilder::Private { public: Private(); GeoDataStyle::ConstPtr presetStyle(GeoDataPlacemark::GeoDataVisualCategory visualCategory) const; GeoDataStyle::Ptr createStyle(qreal width, qreal realWidth, const QColor& color, const QColor& outlineColor, bool fill, bool outline, Qt::BrushStyle brushStyle, Qt::PenStyle penStyle, Qt::PenCapStyle capStyle, bool lineBackground, const QVector< qreal >& dashPattern, const QFont& font, const QColor& fontColor = Qt::black, const QString& texturePath = QString()) const; GeoDataStyle::Ptr createPOIStyle(const QFont &font, const QString &bitmap, const QColor &textColor = Qt::black, const QColor &color = QColor(0xBE, 0xAD, 0xAD), const QColor &outline = QColor(0xBE, 0xAD, 0xAD).darker(), bool fill = true, bool renderOutline = true) const; GeoDataStyle::Ptr createOsmPOIStyle(const QFont &font, const QString &bitmap, const QColor &textColor = Qt::black, const QColor &color = QColor(0xBE, 0xAD, 0xAD), const QColor &outline = QColor(0xBE, 0xAD, 0xAD).darker()) const; GeoDataStyle::Ptr createOsmPOIRingStyle(const QFont &font, const QString &bitmap, const QColor &textColor = Qt::black, const QColor &color = QColor(0xBE, 0xAD, 0xAD), const QColor &outline = QColor(0xBE, 0xAD, 0xAD).darker()) const; GeoDataStyle::Ptr createOsmPOIAreaStyle(const QFont &font, const QString &bitmap, const QColor &textColor = Qt::black, const QColor &color = QColor(0xBE, 0xAD, 0xAD), const QColor &outline = QColor(0xBE, 0xAD, 0xAD).darker()) const; GeoDataStyle::Ptr createHighwayStyle(const QColor& color, const QColor& outlineColor, const QFont& font, const QColor& fontColor = Qt::black, qreal width = 1, qreal realWidth = 0.0, Qt::PenStyle penStyle = Qt::SolidLine, Qt::PenCapStyle capStyle = Qt::RoundCap, bool lineBackground = false) const; GeoDataStyle::Ptr createWayStyle(const QColor& color, const QColor& outlineColor, bool fill = true, bool outline = true, Qt::BrushStyle brushStyle = Qt::SolidPattern, const QString& texturePath = QString()) const; GeoDataStyle::Ptr createIconWayStyle(const QColor& color, const QFont &font, const QColor &textColor, double lineWidth=1.0, const QString& iconPath = QString()) const; GeoDataStyle::ConstPtr createRelationStyle(const StyleParameters ¶meters); GeoDataStyle::ConstPtr createPlacemarkStyle(const StyleParameters ¶meters); GeoDataStyle::ConstPtr adjustPisteStyle(const StyleParameters ¶meters, const GeoDataStyle::ConstPtr &style); void adjustWayWidth(const StyleParameters ¶meters, GeoDataLineStyle &lineStyle) const; // Having an outline with the same color as the fill results in degraded // performance and degraded display quality for no good reason // Q_ASSERT( !(outline && color == outlineColor && brushStyle == Qt::SolidPattern) ); void initializeDefaultStyles(); static QString createPaintLayerItem(const QString &itemType, GeoDataPlacemark::GeoDataVisualCategory visualCategory, const QString &subType = QString()); static void initializeOsmVisualCategories(); static void initializeMinimumZoomLevels(); int m_maximumZoomLevel; QColor m_defaultLabelColor; QFont m_defaultFont; GeoDataStyle::Ptr m_defaultStyle[GeoDataPlacemark::LastIndex]; GeoDataStyle::Ptr m_styleTreeAutumn; GeoDataStyle::Ptr m_styleTreeWinter; bool m_defaultStyleInitialized; QHash m_styleCache; QHash m_buildingStyles; QSet m_oceanianCountries; /** * @brief s_visualCategories contains osm tag mappings to GeoDataVisualCategories */ static QHash s_visualCategories; static int s_defaultMinZoomLevels[GeoDataPlacemark::LastIndex]; static bool s_defaultMinZoomLevelsInitialized; static QHash s_popularities; }; QHash StyleBuilder::Private::s_visualCategories; int StyleBuilder::Private::s_defaultMinZoomLevels[GeoDataPlacemark::LastIndex]; bool StyleBuilder::Private::s_defaultMinZoomLevelsInitialized = false; QHash StyleBuilder::Private::s_popularities; StyleBuilder::Private::Private() : m_maximumZoomLevel(15), m_defaultLabelColor(Qt::black), m_defaultFont(QStringLiteral("Sans Serif")), m_defaultStyle(), m_defaultStyleInitialized(false), m_oceanianCountries( { QLocale::Australia, QLocale::NewZealand, QLocale::Fiji, QLocale::PapuaNewGuinea, QLocale::NewCaledonia, QLocale::SolomonIslands, QLocale::Samoa, QLocale::Vanuatu, QLocale::Guam, QLocale::FrenchPolynesia, QLocale::Tonga, QLocale::Palau, QLocale::Kiribati, QLocale::CookIslands, QLocale::Micronesia, QLocale::MarshallIslands, QLocale::NauruCountry, QLocale::AmericanSamoa, QLocale::Niue, QLocale::Pitcairn, QLocale::WallisAndFutunaIslands, QLocale::NorfolkIsland }) { #if QT_VERSION >= 0x050700 m_oceanianCountries << QLocale::TuvaluCountry << QLocale::OutlyingOceania; #else m_oceanianCountries << QLocale::Tuvalu; #endif initializeMinimumZoomLevels(); for (int i = 0; i < GeoDataPlacemark::LastIndex; ++i) { m_maximumZoomLevel = qMax(m_maximumZoomLevel, s_defaultMinZoomLevels[i]); } } GeoDataStyle::Ptr StyleBuilder::Private::createPOIStyle(const QFont &font, const QString &path, const QColor &textColor, const QColor &color, const QColor &outlineColor, bool fill, bool renderOutline) const { GeoDataStyle::Ptr style = createStyle(1, 0, color, outlineColor, fill, renderOutline, Qt::SolidPattern, Qt::SolidLine, Qt::RoundCap, false, QVector(), font); style->setIconStyle(GeoDataIconStyle(path)); auto const screen = QApplication::screens().first(); double const physicalSize = 6.0; // mm int const pixelSize = qRound(physicalSize * screen->physicalDotsPerInch() / (IN2M * M2MM)); style->iconStyle().setSize(QSize(pixelSize, pixelSize)); style->setLabelStyle(GeoDataLabelStyle(font, textColor)); style->labelStyle().setAlignment(GeoDataLabelStyle::Center); return style; } GeoDataStyle::Ptr StyleBuilder::Private::createOsmPOIStyle(const QFont &font, const QString &imagePath, const QColor &textColor, const QColor &color, const QColor &outlineColor) const { QString const path = MarbleDirs::path(QLatin1String("svg/osmcarto/svg/") + imagePath + QLatin1String(".svg")); return createPOIStyle(font, path, textColor, color, outlineColor, false, false); } GeoDataStyle::Ptr StyleBuilder::Private::createOsmPOIRingStyle(const QFont &font, const QString &imagePath, const QColor &textColor, const QColor &color, const QColor &outlineColor) const { QString const path = MarbleDirs::path(QLatin1String("svg/osmcarto/svg/") + imagePath + QLatin1String(".svg")); return createPOIStyle(font, path, textColor, color, outlineColor, false, true); } GeoDataStyle::Ptr StyleBuilder::Private::createOsmPOIAreaStyle(const QFont &font, const QString &imagePath, const QColor &textColor, const QColor &color, const QColor &outlineColor) const { QString const path = MarbleDirs::path(QLatin1String("svg/osmcarto/svg/") + imagePath + QLatin1String(".svg")); return createPOIStyle(font, path, textColor, color, outlineColor, true, false); } GeoDataStyle::Ptr StyleBuilder::Private::createHighwayStyle(const QColor& color, const QColor& outlineColor, const QFont& font, const QColor& fontColor, qreal width, qreal realWidth, Qt::PenStyle penStyle, Qt::PenCapStyle capStyle, bool lineBackground) const { return createStyle(width, realWidth, color, outlineColor, true, true, Qt::SolidPattern, penStyle, capStyle, lineBackground, QVector< qreal >(), font, fontColor); } GeoDataStyle::Ptr StyleBuilder::Private::createWayStyle(const QColor& color, const QColor& outlineColor, bool fill, bool outline, Qt::BrushStyle brushStyle, const QString& texturePath) const { return createStyle(1, 0, color, outlineColor, fill, outline, brushStyle, Qt::SolidLine, Qt::RoundCap, false, QVector(), m_defaultFont, Qt::black, texturePath); } GeoDataStyle::Ptr StyleBuilder::Private::createIconWayStyle(const QColor &color, const QFont &font, const QColor &textColor, double lineWidth, const QString &iconPath) const { auto const path = iconPath.isEmpty() ? iconPath : MarbleDirs::path(iconPath); auto style = createPOIStyle(font, path, textColor, color, color, true, true); style->lineStyle().setWidth(float(lineWidth)); return style; } GeoDataStyle::ConstPtr StyleBuilder::Private::createRelationStyle(const StyleParameters ¶meters) { Q_ASSERT(parameters.relation); const GeoDataPlacemark *const placemark = parameters.placemark; auto const visualCategory = placemark->visualCategory(); bool const isHighway = visualCategory >= GeoDataPlacemark::HighwaySteps && visualCategory <= GeoDataPlacemark::HighwayMotorway; bool const isRailway = visualCategory >= GeoDataPlacemark::RailwayRail && visualCategory <= GeoDataPlacemark::RailwayFunicular; if (isHighway || isRailway) { if (parameters.relation->relationType() == GeoDataRelation::RouteHiking && parameters.relation->osmData().containsTagKey(QStringLiteral("osmc:symbol"))) { QString const osmcSymbolValue = parameters.relation->osmData().tagValue(QStringLiteral("osmc:symbol")); // Take cached Style instance if possible QString const cacheKey = QStringLiteral("/route/hiking/%1").arg(osmcSymbolValue); if (m_styleCache.contains(cacheKey)) { return m_styleCache[cacheKey]; } auto style = presetStyle(visualCategory); auto lineStyle = style->lineStyle(); if (isHighway) { adjustWayWidth(parameters, lineStyle); } auto iconStyle = style->iconStyle(); GeoDataStyle::Ptr newStyle(new GeoDataStyle(*style)); OsmcSymbol symbol = OsmcSymbol(osmcSymbolValue); lineStyle.setColor(symbol.wayColor()); iconStyle.setIcon(symbol.icon()); newStyle->setLineStyle(lineStyle); newStyle->setIconStyle(iconStyle); style = newStyle; m_styleCache.insert(cacheKey, newStyle); return style; } if (parameters.relation->relationType() >= GeoDataRelation::RouteRoad && parameters.relation->relationType() <= GeoDataRelation::RouteInlineSkates) { auto const colorValue = parameters.relation->osmData().tagValue(QStringLiteral("colour")); QString color = colorValue; if (!QColor::isValidColor(colorValue)) { switch (parameters.relation->relationType()) { case GeoDataRelation::RouteTrain: color = QStringLiteral("navy"); break; case GeoDataRelation::RouteSubway: color = QStringLiteral("cornflowerblue"); break; case GeoDataRelation::RouteTram: color = QStringLiteral("steelblue"); break; case GeoDataRelation::RouteBus: case GeoDataRelation::RouteTrolleyBus: color = QStringLiteral("tomato"); break; case GeoDataRelation::RouteBicycle: case GeoDataRelation::RouteMountainbike: case GeoDataRelation::RouteFoot: case GeoDataRelation::RouteHiking: case GeoDataRelation::RouteHorse: case GeoDataRelation::RouteInlineSkates: color = QStringLiteral("paleturquoise"); break; case GeoDataRelation::UnknownType: case GeoDataRelation:: RouteRoad: case GeoDataRelation::RouteDetour: case GeoDataRelation::RouteFerry: case GeoDataRelation::RouteSkiDownhill: case GeoDataRelation::RouteSkiNordic: case GeoDataRelation::RouteSkitour: case GeoDataRelation::RouteSled: color = QString(); break; } } // Take cached Style instance if possible QString const cacheKey = QStringLiteral("/route/%1/%2").arg(parameters.relation->relationType()).arg(color); if (m_styleCache.contains(cacheKey)) { return m_styleCache[cacheKey]; } auto style = presetStyle(visualCategory); auto lineStyle = style->lineStyle(); if (isHighway) { adjustWayWidth(parameters, lineStyle); } GeoDataStyle::Ptr newStyle(new GeoDataStyle(*style)); if (!color.isEmpty()) { lineStyle.setColor(QColor(color)); auto labelStyle = style->labelStyle(); labelStyle.setColor(GeoDataColorStyle::contrastColor(color)); newStyle->setLabelStyle(labelStyle); } newStyle->setLineStyle(lineStyle); style = newStyle; m_styleCache.insert(cacheKey, newStyle); return style; } } return GeoDataStyle::ConstPtr(); } GeoDataStyle::ConstPtr StyleBuilder::Private::createPlacemarkStyle(const StyleParameters ¶meters) { const GeoDataPlacemark *const placemark = parameters.placemark; QString styleCacheKey; OsmPlacemarkData const & osmData = placemark->osmData(); auto const visualCategory = placemark->visualCategory(); if (visualCategory == GeoDataPlacemark::Building) { auto const tagMap = osmTagMapping(); auto const & osmData = placemark->osmData(); auto const buildingTag = QStringLiteral("building"); for (auto iter = osmData.tagsBegin(), end = osmData.tagsEnd(); iter != end; ++iter) { auto const osmTag = StyleBuilder::OsmTag(iter.key(), iter.value()); if (iter.key() != buildingTag && tagMap.contains(osmTag)) { return m_buildingStyles.value(tagMap.value(osmTag), m_defaultStyle[visualCategory]); } } } GeoDataStyle::ConstPtr style = presetStyle(visualCategory); - if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPointType) { + if (geodata_cast(placemark->geometry())) { if (visualCategory == GeoDataPlacemark::NaturalTree) { GeoDataCoordinates const coordinates = placemark->coordinate(); qreal const lat = coordinates.latitude(GeoDataCoordinates::Degree); if (qAbs(lat) > 15) { /** @todo Should maybe auto-adjust to MarbleClock at some point */ int const month = QDate::currentDate().month(); bool const southernHemisphere = lat < 0; if (southernHemisphere) { if (month >= 3 && month <= 5) { style = m_styleTreeAutumn; } else if (month >= 6 && month <= 8) { style = m_styleTreeWinter; } } else { if (month >= 9 && month <= 11) { style = m_styleTreeAutumn; } else if (month == 12 || month == 1 || month == 2) { style = m_styleTreeWinter; } } } } - } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType) { + } else if (geodata_cast(placemark->geometry())) { bool adjustStyle = false; GeoDataPolyStyle polyStyle = style->polyStyle(); GeoDataLineStyle lineStyle = style->lineStyle(); if (visualCategory == GeoDataPlacemark::NaturalWater) { if (osmData.containsTag(QStringLiteral("salt"), QStringLiteral("yes"))) { polyStyle.setColor("#ffff80"); lineStyle.setPenStyle(Qt::DashLine); lineStyle.setWidth(2); adjustStyle = true; } } else if (visualCategory == GeoDataPlacemark::Bathymetry) { auto tagIter = osmData.findTag(QStringLiteral("ele")); if (tagIter != osmData.tagsEnd()) { const QString& elevation = tagIter.value(); if (elevation == QLatin1String("4000")) { polyStyle.setColor("#94c2c2"); lineStyle.setColor("#94c2c2"); adjustStyle = true; } } } else if (visualCategory == GeoDataPlacemark::AmenityGraveyard || visualCategory == GeoDataPlacemark::LanduseCemetery) { auto tagIter = osmData.findTag(QStringLiteral("religion")); if (tagIter != osmData.tagsEnd()) { const QString& religion = tagIter.value(); if (religion == QLatin1String("jewish")) { polyStyle.setTexturePath(MarbleDirs::path("bitmaps/osmcarto/patterns/grave_yard_jewish.png")); adjustStyle = true; } else if (religion == QLatin1String("christian")) { polyStyle.setTexturePath(MarbleDirs::path("bitmaps/osmcarto/patterns/grave_yard_christian.png")); adjustStyle = true; } else if (religion == QLatin1String("INT-generic")) { polyStyle.setTexturePath(MarbleDirs::path("bitmaps/osmcarto/patterns/grave_yard_generic.png")); adjustStyle = true; } } } else if (visualCategory == GeoDataPlacemark::PisteDownhill) { return adjustPisteStyle(parameters, style); } if (adjustStyle) { GeoDataStyle::Ptr newStyle(new GeoDataStyle(*style)); newStyle->setPolyStyle(polyStyle); newStyle->setLineStyle(lineStyle); style = newStyle; } if (style->iconStyle().iconPath().isEmpty()) { const GeoDataPlacemark::GeoDataVisualCategory category = determineVisualCategory(osmData); const GeoDataStyle::ConstPtr categoryStyle = presetStyle(category); if (category != GeoDataPlacemark::None && !categoryStyle->iconStyle().scaledIcon().isNull()) { GeoDataStyle::Ptr newStyle(new GeoDataStyle(*style)); newStyle->setIconStyle(categoryStyle->iconStyle()); style = newStyle; } } - } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType) { + } else if (geodata_cast(placemark->geometry())) { GeoDataPolyStyle polyStyle = style->polyStyle(); GeoDataLineStyle lineStyle = style->lineStyle(); GeoDataLabelStyle labelStyle = style->labelStyle(); GeoDataIconStyle iconStyle = style->iconStyle(); lineStyle.setCosmeticOutline(true); bool adjustStyle = false; if (visualCategory == GeoDataPlacemark::AdminLevel2) { if (osmData.containsTag(QStringLiteral("maritime"), QStringLiteral("yes"))) { lineStyle.setColor("#88b3bf"); polyStyle.setColor("#88b3bf"); if (osmData.containsTag(QStringLiteral("marble:disputed"), QStringLiteral("yes"))) { lineStyle.setPenStyle(Qt::DashLine); } adjustStyle = true; } } else if ((visualCategory >= GeoDataPlacemark::HighwayService && visualCategory <= GeoDataPlacemark::HighwayMotorway) || visualCategory == GeoDataPlacemark::TransportAirportRunway) { // Take cached Style instance if possible styleCacheKey = QStringLiteral("%1/%2").arg(parameters.tileLevel).arg(visualCategory); if (m_styleCache.contains(styleCacheKey)) { style = m_styleCache[styleCacheKey]; return style; } adjustStyle = true; styleCacheKey = QStringLiteral("%1/%2").arg(parameters.tileLevel).arg(visualCategory); adjustWayWidth(parameters, lineStyle); QString const accessValue = osmData.tagValue(QStringLiteral("access")); if (accessValue == QLatin1String("private") || accessValue == QLatin1String("no") || accessValue == QLatin1String("agricultural") || accessValue == QLatin1String("delivery") || accessValue == QLatin1String("forestry")) { QColor polyColor = polyStyle.color(); qreal hue, sat, val; polyColor.getHsvF(&hue, &sat, &val); polyColor.setHsvF(0.98, qMin(1.0, 0.2 + sat), val); polyStyle.setColor(polyColor); lineStyle.setColor(lineStyle.color().darker(150)); } if (osmData.containsTag("tunnel", "yes")) { QColor polyColor = polyStyle.color(); qreal hue, sat, val; polyColor.getHsvF(&hue, &sat, &val); polyColor.setHsvF(hue, 0.25 * sat, 0.95 * val); polyStyle.setColor(polyColor); lineStyle.setColor(lineStyle.color().lighter(115)); } } else if (visualCategory >= GeoDataPlacemark::WaterwayCanal && visualCategory <= GeoDataPlacemark::WaterwayStream) { adjustStyle = true; // Take cached Style instance if possible styleCacheKey = QStringLiteral("%1/%2").arg(parameters.tileLevel).arg(visualCategory); if (m_styleCache.contains(styleCacheKey)) { style = m_styleCache[styleCacheKey]; return style; } if (parameters.tileLevel <= 3) { lineStyle.setWidth(1); lineStyle.setPhysicalWidth(0.0); styleCacheKey = QStringLiteral("%1/%2").arg(parameters.tileLevel).arg(visualCategory); } else if (parameters.tileLevel <= 7) { lineStyle.setWidth(2); lineStyle.setPhysicalWidth(0.0); styleCacheKey = QStringLiteral("%1/%2").arg(parameters.tileLevel).arg(visualCategory); } else { QString const widthValue = osmData.tagValue(QStringLiteral("width")).remove(QStringLiteral(" meters")).remove(QStringLiteral(" m")); bool ok; float const width = widthValue.toFloat(&ok); lineStyle.setPhysicalWidth(ok ? qBound(0.1f, width, 200.0f) : 0.0f); } } else if (visualCategory == GeoDataPlacemark::PisteDownhill) { return adjustPisteStyle(parameters, style); } if (adjustStyle) { GeoDataStyle::Ptr newStyle(new GeoDataStyle(*style)); newStyle->setPolyStyle(polyStyle); newStyle->setLineStyle(lineStyle); newStyle->setLabelStyle(labelStyle); newStyle->setIconStyle(iconStyle); style = newStyle; if (!styleCacheKey.isEmpty()) { m_styleCache.insert(styleCacheKey, newStyle); } } - } else if (placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) { + } else if (geodata_cast(placemark->geometry())) { GeoDataPolyStyle polyStyle = style->polyStyle(); GeoDataLineStyle lineStyle = style->lineStyle(); bool adjustStyle = false; if (visualCategory == GeoDataPlacemark::Bathymetry) { auto tagIter = osmData.findTag(QStringLiteral("ele")); if (tagIter != osmData.tagsEnd()) { const QString& elevation = tagIter.value(); if (elevation == QLatin1String("4000")) { polyStyle.setColor("#a5c9c9"); lineStyle.setColor("#a5c9c9"); adjustStyle = true; } } } else if (visualCategory == GeoDataPlacemark::PisteDownhill) { return adjustPisteStyle(parameters, style); } if (adjustStyle) { GeoDataStyle::Ptr newStyle(new GeoDataStyle(*style)); newStyle->setPolyStyle(polyStyle); newStyle->setLineStyle(lineStyle); style = newStyle; } } return style; } GeoDataStyle::ConstPtr StyleBuilder::Private::adjustPisteStyle(const StyleParameters ¶meters, const GeoDataStyle::ConstPtr &style) { // Take cached Style instance if possible auto const & osmData = parameters.placemark->osmData(); auto const visualCategory = parameters.placemark->visualCategory(); auto const difficulty = osmData.tagValue("piste:difficulty"); QString styleCacheKey = QStringLiteral("piste/%1/%2").arg(visualCategory).arg(difficulty); if (m_styleCache.contains(styleCacheKey)) { return m_styleCache[styleCacheKey]; } GeoDataLineStyle lineStyle = style->lineStyle(); auto green = QColor("#006600");; auto red = QColor("#cc0000"); auto black = QColor("#151515"); auto yellow = Qt::yellow; auto blue = QColor("#000099"); auto orange = QColor(255, 165, 0); auto fallBack = Qt::lightGray; auto country = QLocale::system().country(); if (country == QLocale::Japan) { if (difficulty == "easy") { lineStyle.setColor(green); } else if (difficulty == "intermediate") { lineStyle.setColor(red); } else if (difficulty == "advanced") { lineStyle.setColor(black); } else { lineStyle.setColor(fallBack); } } else if (country == QLocale::UnitedStates || country == QLocale::UnitedStatesMinorOutlyingIslands || country == QLocale::Canada || m_oceanianCountries.contains(country)) { if (difficulty == "easy") { lineStyle.setColor(green); } else if (difficulty == "intermediate") { lineStyle.setColor(blue); } else if (difficulty == "advanced" || difficulty == "expert") { lineStyle.setColor(black); } else { lineStyle.setColor(fallBack); } // fallback on Europe } else { if (difficulty == "novice") { lineStyle.setColor(green); } else if (difficulty == "easy") { lineStyle.setColor(blue); } else if (difficulty == "intermediate") { lineStyle.setColor(red); } else if (difficulty == "advanced") { lineStyle.setColor(black); } else if (difficulty == "expert") { // scandinavian countries have different colors then the rest of Europe if (country == QLocale::Denmark || country == QLocale::Norway || country == QLocale::Sweden) { lineStyle.setColor(black); } else { lineStyle.setColor(orange); } } else if (difficulty == "freeride") { lineStyle.setColor(yellow); } else { lineStyle.setColor(fallBack); } } GeoDataPolyStyle polyStyle = style->polyStyle(); polyStyle.setColor(lineStyle.color()); GeoDataStyle::Ptr newStyle(new GeoDataStyle(*style)); newStyle->setPolyStyle(polyStyle); newStyle->setLineStyle(lineStyle); m_styleCache.insert(styleCacheKey, newStyle); return newStyle; } void StyleBuilder::Private::adjustWayWidth(const StyleParameters ¶meters, GeoDataLineStyle &lineStyle) const { auto const & osmData = parameters.placemark->osmData(); auto const visualCategory = parameters.placemark->visualCategory(); if (parameters.tileLevel <= 8) { lineStyle.setPhysicalWidth(0.0); lineStyle.setWidth(2.0); } else if (parameters.tileLevel <= 10) { lineStyle.setPhysicalWidth(0.0); lineStyle.setWidth(3.0); } else if (parameters.tileLevel <= 12) { lineStyle.setPhysicalWidth(0.0); lineStyle.setWidth(4.0); } else { auto tagIter = osmData.findTag(QStringLiteral("width")); if (tagIter != osmData.tagsEnd()) { QString const widthValue = QString(tagIter.value()).remove(QStringLiteral(" meters")).remove(QStringLiteral(" m")); bool ok; float const width = widthValue.toFloat(&ok); lineStyle.setPhysicalWidth(ok ? qBound(0.1f, width, 200.0f) : 0.0f); } else { bool const isOneWay = osmData.containsTag(QStringLiteral("oneway"), QStringLiteral("yes")) || osmData.containsTag(QStringLiteral("oneway"), QStringLiteral("-1")); int const lanes = isOneWay ? 1 : 2; // also for motorway which implicitly is one way, but has two lanes and each direction has its own highway double const laneWidth = 3.0; double const margins = visualCategory == GeoDataPlacemark::HighwayMotorway ? 2.0 : (isOneWay ? 1.0 : 0.0); double const physicalWidth = margins + lanes * laneWidth; lineStyle.setPhysicalWidth(physicalWidth); } } } GeoDataStyle::Ptr StyleBuilder::Private::createStyle(qreal width, qreal realWidth, const QColor& color, const QColor& outlineColor, bool fill, bool outline, Qt::BrushStyle brushStyle, Qt::PenStyle penStyle, Qt::PenCapStyle capStyle, bool lineBackground, const QVector< qreal >& dashPattern, const QFont& font, const QColor& fontColor, const QString& texturePath) const { GeoDataStyle *style = new GeoDataStyle; GeoDataLineStyle lineStyle(outlineColor); lineStyle.setCapStyle(capStyle); lineStyle.setPenStyle(penStyle); lineStyle.setWidth(width); lineStyle.setPhysicalWidth(realWidth); lineStyle.setBackground(lineBackground); lineStyle.setDashPattern(dashPattern); GeoDataPolyStyle polyStyle(color); polyStyle.setOutline(outline); polyStyle.setFill(fill); polyStyle.setBrushStyle(brushStyle); polyStyle.setTexturePath(texturePath); GeoDataLabelStyle labelStyle(font, fontColor); style->setLineStyle(lineStyle); style->setPolyStyle(polyStyle); style->setLabelStyle(labelStyle); return GeoDataStyle::Ptr(style); } void StyleBuilder::Private::initializeDefaultStyles() { // We need to do this similar to the way KCmdLineOptions works in // the future: Having a PlacemarkStyleProperty properties[] would // help here greatly. if (m_defaultStyleInitialized) { return; } m_defaultStyleInitialized = true; QString defaultFamily = m_defaultFont.family(); #ifdef Q_OS_MACX int defaultSize = 10; #else int defaultSize = 8; #endif QColor const defaultLabelColor = m_defaultLabelColor; m_defaultStyle[GeoDataPlacemark::None] = GeoDataStyle::Ptr(new GeoDataStyle(QString(), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Default] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/default_location.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Unknown] = GeoDataStyle::Ptr(new GeoDataStyle(QString(), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::SmallCity] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_4_white.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::SmallCountyCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_4_yellow.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::SmallStateCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_4_orange.png"), QFont(defaultFamily, defaultSize, 50, true), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::SmallNationCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_4_red.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::MediumCity] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_3_white.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::MediumCountyCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_3_yellow.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::MediumStateCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_3_orange.png"), QFont(defaultFamily, defaultSize, 50, true), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::MediumNationCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_3_red.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::BigCity] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_2_white.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::BigCountyCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_2_yellow.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::BigStateCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_2_orange.png"), QFont(defaultFamily, defaultSize, 50, true), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::BigNationCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_2_red.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::LargeCity] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_1_white.png"), QFont(defaultFamily, defaultSize, 75, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::LargeCountyCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_1_yellow.png"), QFont(defaultFamily, defaultSize, 75, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::LargeStateCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_1_orange.png"), QFont(defaultFamily, defaultSize, 75, true), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::LargeNationCapital] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/city_1_red.png"), QFont(defaultFamily, defaultSize, 75, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Nation] = GeoDataStyle::Ptr(new GeoDataStyle(QString(), QFont(defaultFamily, int(defaultSize * 1.5), 75, false), QColor("#404040"))); // Align area labels centered m_defaultStyle[GeoDataPlacemark::Nation]->labelStyle().setAlignment(GeoDataLabelStyle::Center); QFont osmCityFont = QFont(defaultFamily, int(defaultSize * 1.5), 75, false); m_defaultStyle[GeoDataPlacemark::PlaceCity] = createOsmPOIStyle(osmCityFont, "place/place-6", QColor("#202020")); m_defaultStyle[GeoDataPlacemark::PlaceCityCapital] = createOsmPOIStyle(osmCityFont, "place/place-capital-6", QColor("#202020")); m_defaultStyle[GeoDataPlacemark::PlaceCityNationalCapital] = createOsmPOIStyle(osmCityFont, "place/place-capital-adminlevel2", QColor("#202020")); m_defaultStyle[GeoDataPlacemark::PlaceSuburb] = createOsmPOIStyle(osmCityFont, QString(), QColor("#707070")); m_defaultStyle[GeoDataPlacemark::PlaceHamlet] = createOsmPOIStyle(osmCityFont, QString(), QColor("#707070")); QFont localityFont = osmCityFont; localityFont.setPointSize(defaultSize); m_defaultStyle[GeoDataPlacemark::PlaceLocality] = createOsmPOIStyle(localityFont, QString(), QColor("#707070")); m_defaultStyle[GeoDataPlacemark::PlaceTown] = createOsmPOIStyle(osmCityFont, "place/place-6", QColor("#404040")); m_defaultStyle[GeoDataPlacemark::PlaceTownCapital] = createOsmPOIStyle(osmCityFont, "place/place-capital-6", QColor("#404040")); m_defaultStyle[GeoDataPlacemark::PlaceTownNationalCapital] = createOsmPOIStyle(osmCityFont, "place/place-capital-adminlevel2", QColor("#404040")); m_defaultStyle[GeoDataPlacemark::PlaceVillage] = createOsmPOIStyle(osmCityFont, "place/place-6", QColor("#505050")); m_defaultStyle[GeoDataPlacemark::PlaceVillageCapital] = createOsmPOIStyle(osmCityFont, "place/place-capital-6", QColor("#505050")); m_defaultStyle[GeoDataPlacemark::PlaceVillageNationalCapital] = createOsmPOIStyle(osmCityFont, "place/place-capital-adminlevel2", QColor("#505050")); for (int i = GeoDataPlacemark::PlaceCity; i <= GeoDataPlacemark::PlaceVillageCapital; ++i) { m_defaultStyle[GeoDataPlacemark::GeoDataVisualCategory(i)]->polyStyle().setFill(false); m_defaultStyle[GeoDataPlacemark::GeoDataVisualCategory(i)]->polyStyle().setOutline(false); m_defaultStyle[GeoDataPlacemark::GeoDataVisualCategory(i)]->labelStyle().setAlignment(GeoDataLabelStyle::Center); if (i == GeoDataPlacemark::PlaceCityNationalCapital || i == GeoDataPlacemark::PlaceTownNationalCapital || i == GeoDataPlacemark::PlaceVillageNationalCapital) { m_defaultStyle[GeoDataPlacemark::GeoDataVisualCategory(i)]->iconStyle().setScale(0.55f); } else { m_defaultStyle[GeoDataPlacemark::GeoDataVisualCategory(i)]->iconStyle().setScale(0.25); } } m_defaultStyle[GeoDataPlacemark::Mountain] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/mountain_1.png"), QFont(defaultFamily, int(defaultSize * 0.9), 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Volcano] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/volcano_1.png"), QFont(defaultFamily, int(defaultSize * 0.9), 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Mons] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/mountain_1.png"), QFont(defaultFamily, int(defaultSize * 0.9), 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Valley] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/valley.png"), QFont(defaultFamily, int(defaultSize * 0.9), 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Continent] = GeoDataStyle::Ptr(new GeoDataStyle(QString(), QFont(defaultFamily, int(defaultSize * 1.7), 50, false), QColor("#bf0303"))); // Align area labels centered m_defaultStyle[GeoDataPlacemark::Continent]->labelStyle().setAlignment(GeoDataLabelStyle::Center); m_defaultStyle[GeoDataPlacemark::Ocean] = GeoDataStyle::Ptr(new GeoDataStyle(QString(), QFont(defaultFamily, int(defaultSize * 1.7), 50, true), QColor("#2c72c7"))); // Align area labels centered m_defaultStyle[GeoDataPlacemark::Ocean]->labelStyle().setAlignment(GeoDataLabelStyle::Center); m_defaultStyle[GeoDataPlacemark::OtherTerrain] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/other.png"), QFont(defaultFamily, int(defaultSize * 0.9), 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Crater] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/crater.png"), QFont(defaultFamily, int(defaultSize * 0.9), 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Mare] = GeoDataStyle::Ptr(new GeoDataStyle(QString(), QFont(defaultFamily, int(defaultSize * 1.7), 50, false), QColor("#bf0303"))); // Align area labels centered m_defaultStyle[GeoDataPlacemark::Mare]->labelStyle().setAlignment(GeoDataLabelStyle::Center); m_defaultStyle[GeoDataPlacemark::GeographicPole] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/pole_1.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::MagneticPole] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/pole_2.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::ShipWreck] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/shipwreck.png"), QFont(defaultFamily, int(defaultSize * 0.8), 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::AirPort] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/airport.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Observatory] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/observatory.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::OsmSite] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/osm.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Coordinate] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/coordinate.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::MannedLandingSite] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/manned_landing.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::RoboticRover] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/robotic_rover.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::UnmannedSoftLandingSite] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/unmanned_soft_landing.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::UnmannedHardLandingSite] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/unmanned_hard_landing.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); m_defaultStyle[GeoDataPlacemark::Bookmark] = createPOIStyle(QFont(defaultFamily, defaultSize, 50, false), MarbleDirs::path("svg/bookmark.svg"), defaultLabelColor); m_defaultStyle[GeoDataPlacemark::Bookmark]->iconStyle().setScale(0.75); QColor const shopColor("#ac39ac"); QColor const transportationColor("#0092da"); QColor const amenityColor("#734a08"); QColor const healthColor("#da0092"); QColor const airTransportColor("#8461C4"); QColor const educationalAreasAndHospital("#f0f0d8"); QColor const buildingColor("#beadad"); QColor const waterColor("#b5d0d0"); // Allows to visualize multiple repaints of buildings // QColor const buildingColor(0, 255, 0, 64); QFont const osmFont(defaultFamily, 10, 50, false); m_defaultStyle[GeoDataPlacemark::AccomodationCamping] = createOsmPOIRingStyle(osmFont, "transportation/camping.16", transportationColor); m_defaultStyle[GeoDataPlacemark::AccomodationHostel] = createOsmPOIStyle(osmFont, "transportation/hostel.16", transportationColor); m_defaultStyle[GeoDataPlacemark::AccomodationHotel] = createOsmPOIStyle(osmFont, "transportation/hotel.16", transportationColor); m_defaultStyle[GeoDataPlacemark::AccomodationMotel] = createOsmPOIStyle(osmFont, "transportation/motel.16", transportationColor); m_defaultStyle[GeoDataPlacemark::AccomodationYouthHostel] = createOsmPOIStyle(osmFont, "transportation/hostel.16", transportationColor); m_defaultStyle[GeoDataPlacemark::AccomodationGuestHouse] = createOsmPOIStyle(osmFont, "transportation/guest_house.16", transportationColor); m_defaultStyle[GeoDataPlacemark::AmenityLibrary] = createOsmPOIStyle(osmFont, "amenity/library.20", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityKindergarten] = createOsmPOIAreaStyle(osmFont, QString(), amenityColor, educationalAreasAndHospital, amenityColor); m_defaultStyle[GeoDataPlacemark::EducationCollege] = createOsmPOIAreaStyle(osmFont, QString(), amenityColor, educationalAreasAndHospital, amenityColor); m_defaultStyle[GeoDataPlacemark::EducationSchool] = createOsmPOIAreaStyle(osmFont, QString(), amenityColor, educationalAreasAndHospital, amenityColor); m_defaultStyle[GeoDataPlacemark::EducationUniversity] = createOsmPOIAreaStyle(osmFont, QString(), amenityColor, educationalAreasAndHospital, amenityColor); m_defaultStyle[GeoDataPlacemark::FoodBar] = createOsmPOIStyle(osmFont, "amenity/bar.16", amenityColor); m_defaultStyle[GeoDataPlacemark::FoodBiergarten] = createOsmPOIStyle(osmFont, "amenity/biergarten.16", amenityColor); m_defaultStyle[GeoDataPlacemark::FoodCafe] = createOsmPOIStyle(osmFont, "amenity/cafe.16", amenityColor); m_defaultStyle[GeoDataPlacemark::FoodFastFood] = createOsmPOIStyle(osmFont, "amenity/fast_food.16", amenityColor); m_defaultStyle[GeoDataPlacemark::FoodPub] = createOsmPOIStyle(osmFont, "amenity/pub.16", amenityColor); m_defaultStyle[GeoDataPlacemark::FoodRestaurant] = createOsmPOIStyle(osmFont, "amenity/restaurant.16", amenityColor); m_defaultStyle[GeoDataPlacemark::HealthDentist] = createOsmPOIStyle(osmFont, "health/dentist.16", healthColor); m_defaultStyle[GeoDataPlacemark::HealthDoctors] = createOsmPOIStyle(osmFont, "health/doctors.16", healthColor); m_defaultStyle[GeoDataPlacemark::HealthHospital] = createOsmPOIStyle(osmFont, "health/hospital.16", healthColor, educationalAreasAndHospital, amenityColor); m_defaultStyle[GeoDataPlacemark::HealthPharmacy] = createOsmPOIStyle(osmFont, "health/pharmacy.16", healthColor); m_defaultStyle[GeoDataPlacemark::HealthVeterinary] = createOsmPOIStyle(osmFont, "health/veterinary-14", healthColor); m_defaultStyle[GeoDataPlacemark::MoneyAtm] = createOsmPOIStyle(osmFont, "amenity/atm.16", amenityColor); m_defaultStyle[GeoDataPlacemark::MoneyBank] = createOsmPOIStyle(osmFont, "amenity/bank.16", amenityColor); m_defaultStyle[GeoDataPlacemark::HistoricArchaeologicalSite] = createOsmPOIAreaStyle(osmFont, "amenity/archaeological_site.16", amenityColor, Qt::transparent); m_defaultStyle[GeoDataPlacemark::AmenityEmbassy] = createOsmPOIStyle(osmFont, "transportation/embassy.16", transportationColor); m_defaultStyle[GeoDataPlacemark::AmenityEmergencyPhone] = createOsmPOIStyle(osmFont, "amenity/emergency_phone.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityMountainRescue] = createOsmPOIStyle(osmFont, "amenity/mountain_rescue.16", amenityColor); m_defaultStyle[GeoDataPlacemark::LeisureWaterPark] = createOsmPOIStyle(osmFont, "amenity/water_park.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityCommunityCentre] = createOsmPOIStyle(osmFont, "amenity/community_centre-14", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityFountain] = createOsmPOIStyle(osmFont, "amenity/fountain-14", QColor("#7989de"), waterColor, waterColor.darker(150)); m_defaultStyle[GeoDataPlacemark::AmenityNightClub] = createOsmPOIStyle(osmFont, "amenity/nightclub.18", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityBench] = createOsmPOIStyle(osmFont, "individual/bench.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityCourtHouse] = createOsmPOIStyle(osmFont, "amenity/courthouse-16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityFireStation] = createOsmPOIStyle(osmFont, "amenity/firestation.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityHuntingStand] = createOsmPOIStyle(osmFont, "manmade/hunting-stand.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityPolice] = createOsmPOIStyle(osmFont, "amenity/police.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityPostBox] = createOsmPOIStyle(osmFont, "amenity/post_box-12", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityPostOffice] = createOsmPOIStyle(osmFont, "amenity/post_office-14", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityPrison] = createOsmPOIStyle(osmFont, "amenity/prison.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityRecycling] = createOsmPOIStyle(osmFont, "amenity/recycling.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityShelter] = createOsmPOIStyle(osmFont, "transportation/shelter", transportationColor); m_defaultStyle[GeoDataPlacemark::AmenityTelephone] = createOsmPOIStyle(osmFont, "amenity/telephone.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityToilets] = createOsmPOIStyle(osmFont, "amenity/toilets.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityTownHall] = createOsmPOIStyle(osmFont, "amenity/town_hall.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityWasteBasket] = createOsmPOIStyle(osmFont, "individual/waste_basket.10", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityWasteBasket]->iconStyle().setScale(0.75); m_defaultStyle[GeoDataPlacemark::AmenityChargingStation] = createOsmPOIStyle(osmFont, "transportation/charging_station"); m_defaultStyle[GeoDataPlacemark::AmenityCarWash] = createOsmPOIStyle(osmFont, "amenity/car_wash", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenitySocialFacility] = createOsmPOIStyle(osmFont, "amenity/social_facility", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityDrinkingWater] = createOsmPOIStyle(osmFont, "amenity/drinking_water.16", amenityColor); m_defaultStyle[GeoDataPlacemark::NaturalPeak] = createOsmPOIStyle(osmFont, "individual/peak", amenityColor); m_defaultStyle[GeoDataPlacemark::NaturalPeak]->iconStyle().setScale(0.33f); m_defaultStyle[GeoDataPlacemark::NaturalVolcano] = createOsmPOIStyle(osmFont, "individual/volcano", amenityColor); m_defaultStyle[GeoDataPlacemark::NaturalVolcano]->iconStyle().setScale(0.33f); m_defaultStyle[GeoDataPlacemark::NaturalTree] = createOsmPOIStyle(osmFont, "individual/tree-29", amenityColor); // tree-16 provides the official icon m_styleTreeAutumn = createOsmPOIStyle(osmFont, "individual/tree-29-autumn", amenityColor); m_styleTreeWinter = createOsmPOIStyle(osmFont, "individual/tree-29-winter", amenityColor); qreal const treeIconScale = 0.75; m_defaultStyle[GeoDataPlacemark::NaturalTree]->iconStyle().setScale(treeIconScale); m_styleTreeAutumn->iconStyle().setScale(treeIconScale); m_styleTreeWinter->iconStyle().setScale(treeIconScale); m_defaultStyle[GeoDataPlacemark::ShopBeverages] = createOsmPOIStyle(osmFont, "shop/beverages-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopHifi] = createOsmPOIStyle(osmFont, "shop/hifi-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopSupermarket] = createOsmPOIStyle(osmFont, "shop/shop_supermarket", shopColor); m_defaultStyle[GeoDataPlacemark::ShopAlcohol] = createOsmPOIStyle(osmFont, "shop/shop_alcohol.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopBakery] = createOsmPOIStyle(osmFont, "shop/shop_bakery.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopButcher] = createOsmPOIStyle(osmFont, "shop/butcher-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopConfectionery] = createOsmPOIStyle(osmFont, "shop/confectionery.14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopConvenience] = createOsmPOIStyle(osmFont, "shop/shop_convenience", shopColor); m_defaultStyle[GeoDataPlacemark::ShopGreengrocer] = createOsmPOIStyle(osmFont, "shop/greengrocer-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopSeafood] = createOsmPOIStyle(osmFont, "shop/seafood-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopDepartmentStore] = createOsmPOIStyle(osmFont, "shop/department_store-16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopKiosk] = createOsmPOIStyle(osmFont, "shop/kiosk-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopBag] = createOsmPOIStyle(osmFont, "shop/bag-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopClothes] = createOsmPOIStyle(osmFont, "shop/shop_clothes.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopFashion] = createOsmPOIStyle(osmFont, "shop/shop_clothes.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopJewelry] = createOsmPOIStyle(osmFont, "shop/shop_jewelry.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopShoes] = createOsmPOIStyle(osmFont, "shop/shop_shoes.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopVarietyStore] = createOsmPOIStyle(osmFont, "shop/variety_store-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopBeauty] = createOsmPOIStyle(osmFont, "shop/beauty-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopChemist] = createOsmPOIStyle(osmFont, "shop/chemist-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopCosmetics] = createOsmPOIStyle(osmFont, "shop/perfumery-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopHairdresser] = createOsmPOIStyle(osmFont, "shop/shop_hairdresser.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopOptician] = createOsmPOIStyle(osmFont, "shop/shop_optician.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopPerfumery] = createOsmPOIStyle(osmFont, "shop/perfumery-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopDoitYourself] = createOsmPOIStyle(osmFont, "shop/shop_diy.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopFlorist] = createOsmPOIStyle(osmFont, "shop/florist.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopHardware] = createOsmPOIStyle(osmFont, "shop/shop_diy.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopFurniture] = createOsmPOIStyle(osmFont, "shop/shop_furniture.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopElectronics] = createOsmPOIStyle(osmFont, "shop/shop_electronics.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopMobilePhone] = createOsmPOIStyle(osmFont, "shop/shop_mobile_phone.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopBicycle] = createOsmPOIStyle(osmFont, "shop/shop_bicycle.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopCar] = createOsmPOIStyle(osmFont, "shop/shop_car", shopColor); m_defaultStyle[GeoDataPlacemark::ShopCarRepair] = createOsmPOIStyle(osmFont, "shop/shopping_car_repair.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopCarParts] = createOsmPOIStyle(osmFont, "shop/car_parts-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopMotorcycle] = createOsmPOIStyle(osmFont, "shop/motorcycle-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopOutdoor] = createOsmPOIStyle(osmFont, "shop/outdoor-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopSports] = createOsmPOIStyle(osmFont, "shop/sports", shopColor); m_defaultStyle[GeoDataPlacemark::ShopCopy] = createOsmPOIStyle(osmFont, "shop/copyshop", shopColor); m_defaultStyle[GeoDataPlacemark::ShopArt] = createOsmPOIStyle(osmFont, "shop/art", shopColor); m_defaultStyle[GeoDataPlacemark::ShopMusicalInstrument] = createOsmPOIStyle(osmFont, "shop/musical_instrument-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopPhoto] = createOsmPOIStyle(osmFont, "shop/photo-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopBook] = createOsmPOIStyle(osmFont, "shop/shop_books.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopGift] = createOsmPOIStyle(osmFont, "shop/shop_gift.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopStationery] = createOsmPOIStyle(osmFont, "shop/stationery-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopLaundry] = createOsmPOIStyle(osmFont, "shop/laundry-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopPet] = createOsmPOIStyle(osmFont, "shop/shop_pet.16", shopColor); m_defaultStyle[GeoDataPlacemark::ShopToys] = createOsmPOIStyle(osmFont, "shop/toys-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopTravelAgency] = createOsmPOIStyle(osmFont, "shop/travel_agency-14", shopColor); m_defaultStyle[GeoDataPlacemark::ShopDeli] = createOsmPOIStyle(osmFont, "shop/deli", shopColor); m_defaultStyle[GeoDataPlacemark::ShopTobacco] = createOsmPOIStyle(osmFont, "shop/tobacco", shopColor); m_defaultStyle[GeoDataPlacemark::ShopTea] = createOsmPOIStyle(osmFont, "shop/tea", shopColor); m_defaultStyle[GeoDataPlacemark::Shop] = createOsmPOIStyle(osmFont, "shop/shop-14", shopColor); m_defaultStyle[GeoDataPlacemark::ManmadeBridge] = createWayStyle(QColor("#b8b8b8"), Qt::transparent, true, true); m_defaultStyle[GeoDataPlacemark::ManmadeLighthouse] = createOsmPOIStyle(osmFont, "transportation/lighthouse.16", transportationColor, "#f2efe9", QColor("#f2efe9").darker()); m_defaultStyle[GeoDataPlacemark::ManmadePier] = createStyle(0.0, 3.0, "#f2efe9", "#f2efe9", true, false, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont); m_defaultStyle[GeoDataPlacemark::ManmadeWaterTower] = createOsmPOIStyle(osmFont, "amenity/water_tower.16", amenityColor); m_defaultStyle[GeoDataPlacemark::ManmadeWindMill] = createOsmPOIStyle(osmFont, "amenity/windmill.16", amenityColor); m_defaultStyle[GeoDataPlacemark::HistoricCastle] = createOsmPOIRingStyle(osmFont, "amenity/cinema.16", amenityColor); m_defaultStyle[GeoDataPlacemark::HistoricMemorial] = createOsmPOIStyle(osmFont, "amenity/tourist_memorial.16", amenityColor); m_defaultStyle[GeoDataPlacemark::HistoricMonument] = createOsmPOIStyle(osmFont, "amenity/monument.16", amenityColor); m_defaultStyle[GeoDataPlacemark::HistoricRuins] = createOsmPOIRingStyle(osmFont, QString(), amenityColor); m_defaultStyle[GeoDataPlacemark::TourismAttraction] = createOsmPOIStyle(osmFont, "amenity/tourist_memorial.16", amenityColor); m_defaultStyle[GeoDataPlacemark::TourismArtwork] = createOsmPOIStyle(osmFont, "amenity/artwork", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityCinema] = createOsmPOIStyle(osmFont, "amenity/cinema.16", amenityColor); m_defaultStyle[GeoDataPlacemark::TourismInformation] = createOsmPOIStyle(osmFont, "amenity/information.16", amenityColor); m_defaultStyle[GeoDataPlacemark::TourismMuseum] = createOsmPOIStyle(osmFont, "amenity/museum.16", amenityColor); m_defaultStyle[GeoDataPlacemark::AmenityTheatre] = createOsmPOIStyle(osmFont, "amenity/theatre.16", amenityColor); m_defaultStyle[GeoDataPlacemark::TourismThemePark] = createOsmPOIStyle(osmFont, QString(), amenityColor); m_defaultStyle[GeoDataPlacemark::TourismViewPoint] = createOsmPOIStyle(osmFont, "amenity/viewpoint.16", amenityColor); m_defaultStyle[GeoDataPlacemark::TourismZoo] = createOsmPOIRingStyle(osmFont, QString(), amenityColor, Qt::transparent); m_defaultStyle[GeoDataPlacemark::TourismAlpineHut] = createOsmPOIStyle(osmFont, "transportation/alpinehut.16", transportationColor); m_defaultStyle[GeoDataPlacemark::TourismWildernessHut] = createOsmPOIStyle(osmFont, "transportation/wilderness_hut", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportAerodrome] = createOsmPOIStyle(osmFont, "airtransport/aerodrome", airTransportColor); m_defaultStyle[GeoDataPlacemark::TransportHelipad] = createOsmPOIStyle(osmFont, "airtransport/helipad", airTransportColor); m_defaultStyle[GeoDataPlacemark::TransportAirportTerminal] = createOsmPOIAreaStyle(osmFont, QString(), airTransportColor); m_defaultStyle[GeoDataPlacemark::TransportAirportGate] = createOsmPOIAreaStyle(osmFont, QString(), airTransportColor); m_defaultStyle[GeoDataPlacemark::TransportBusStation] = createOsmPOIStyle(osmFont, "transportation/bus_station.16", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportBusStop] = createOsmPOIStyle(osmFont, "transportation/bus_stop.12", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportCarShare] = createOsmPOIStyle(osmFont, "transportation/car_share.16", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportFuel] = createOsmPOIStyle(osmFont, "transportation/fuel.16", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportParking] = createOsmPOIAreaStyle(osmFont, "transportation/parking", transportationColor, "#F6EEB6", QColor("#F6EEB6").darker()); m_defaultStyle[GeoDataPlacemark::TransportBicycleParking] = createOsmPOIAreaStyle(osmFont, "transportation/bicycle_parking.16", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportMotorcycleParking] = createOsmPOIAreaStyle(osmFont, "transportation/motorcycle_parking.16", transportationColor); qreal const parkingIconScale = 0.75; m_defaultStyle[GeoDataPlacemark::TransportParking]->iconStyle().setScale(parkingIconScale); m_defaultStyle[GeoDataPlacemark::TransportBicycleParking]->iconStyle().setScale(parkingIconScale); m_defaultStyle[GeoDataPlacemark::TransportMotorcycleParking]->iconStyle().setScale(parkingIconScale); m_defaultStyle[GeoDataPlacemark::TransportParkingSpace] = createWayStyle("#F6EEB6", QColor("#F6EEB6").darker(), true, true); m_defaultStyle[GeoDataPlacemark::TransportPlatform] = createWayStyle("#bbbbbb", Qt::transparent, true, false); m_defaultStyle[GeoDataPlacemark::TransportTrainStation] = createOsmPOIStyle(osmFont, "individual/railway_station", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportTrainStation]->iconStyle().setScale(0.5); m_defaultStyle[GeoDataPlacemark::TransportTramStop] = createOsmPOIStyle(osmFont, "individual/railway_station", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportTramStop]->iconStyle().setScale(0.33f); m_defaultStyle[GeoDataPlacemark::TransportRentalBicycle] = createOsmPOIStyle(osmFont, "transportation/rental_bicycle.16", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportRentalCar] = createOsmPOIStyle(osmFont, "transportation/rental_car.16", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportRentalSki] = createOsmPOIStyle(osmFont, "transportation/rental_ski.16", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportTaxiRank] = createOsmPOIStyle(osmFont, "transportation/taxi.16", transportationColor); m_defaultStyle[GeoDataPlacemark::TransportSubwayEntrance] = createOsmPOIStyle(osmFont, "transportation/subway_entrance", transportationColor); m_defaultStyle[GeoDataPlacemark::ReligionPlaceOfWorship] = createOsmPOIStyle(osmFont, QString() /* "black/place_of_worship.16" */); m_defaultStyle[GeoDataPlacemark::ReligionBahai] = createOsmPOIStyle(osmFont, QString()); m_defaultStyle[GeoDataPlacemark::ReligionBuddhist] = createOsmPOIStyle(osmFont, "black/buddhist.16"); m_defaultStyle[GeoDataPlacemark::ReligionChristian] = createOsmPOIStyle(osmFont, "black/christian.16"); m_defaultStyle[GeoDataPlacemark::ReligionMuslim] = createOsmPOIStyle(osmFont, "black/muslim.16"); m_defaultStyle[GeoDataPlacemark::ReligionHindu] = createOsmPOIStyle(osmFont, "black/hinduist.16"); m_defaultStyle[GeoDataPlacemark::ReligionJain] = createOsmPOIStyle(osmFont, QString()); m_defaultStyle[GeoDataPlacemark::ReligionJewish] = createOsmPOIStyle(osmFont, "black/jewish.16"); m_defaultStyle[GeoDataPlacemark::ReligionShinto] = createOsmPOIStyle(osmFont, "black/shintoist.16"); m_defaultStyle[GeoDataPlacemark::ReligionSikh] = createOsmPOIStyle(osmFont, "black/sikhist.16"); m_defaultStyle[GeoDataPlacemark::HighwayTrafficSignals] = createOsmPOIStyle(osmFont, "individual/traffic_light"); m_defaultStyle[GeoDataPlacemark::HighwayTrafficSignals]->iconStyle().setScale(0.75); m_defaultStyle[GeoDataPlacemark::PowerTower] = createOsmPOIStyle(osmFont, "individual/power_tower", QColor("#888888")); m_defaultStyle[GeoDataPlacemark::PowerTower]->iconStyle().setScale(0.6f); m_defaultStyle[GeoDataPlacemark::BarrierCityWall] = createStyle(6.0, 3.0, "#787878", Qt::transparent, true, false, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont, Qt::transparent); m_defaultStyle[GeoDataPlacemark::BarrierGate] = createOsmPOIStyle(osmFont, "individual/gate"); m_defaultStyle[GeoDataPlacemark::BarrierGate]->iconStyle().setScale(0.75); m_defaultStyle[GeoDataPlacemark::BarrierLiftGate] = createOsmPOIStyle(osmFont, "individual/liftgate"); m_defaultStyle[GeoDataPlacemark::BarrierLiftGate]->iconStyle().setScale(0.75); m_defaultStyle[GeoDataPlacemark::BarrierWall] = createStyle(2.0, 0.0, "#787878", Qt::transparent, true, false, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont, Qt::transparent); m_defaultStyle[GeoDataPlacemark::HighwaySteps] = createStyle(0.0, 2.0, "#fa8072", QColor(Qt::white), true, true, Qt::SolidPattern, Qt::CustomDashLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::HighwayUnknown] = createHighwayStyle("#dddddd", "#bbbbbb", osmFont, "000000", 0, 1); m_defaultStyle[GeoDataPlacemark::HighwayPath] = createHighwayStyle("#dddde8", "#999999", osmFont, "000000", 0, 1, Qt::DotLine, Qt::SquareCap, true); m_defaultStyle[GeoDataPlacemark::HighwayTrack] = createHighwayStyle("#996600", QColor(Qt::white), osmFont, QColor(Qt::transparent), 1, 1, Qt::DashLine, Qt::SquareCap, true); m_defaultStyle[GeoDataPlacemark::HighwayPedestrian] = createHighwayStyle("#dddde8", "#999999", osmFont, "000000", 0, 2); m_defaultStyle[GeoDataPlacemark::HighwayPedestrian]->polyStyle().setOutline(false); m_defaultStyle[GeoDataPlacemark::HighwayFootway] = createHighwayStyle("#fa8072", QColor(Qt::white), osmFont, "000000", 0, 2, Qt::DotLine, Qt::SquareCap, true); m_defaultStyle[GeoDataPlacemark::HighwayCycleway] = createHighwayStyle(QColor(Qt::blue), QColor(Qt::white), osmFont, "000000", 0, 2, Qt::DotLine, Qt::SquareCap, true); m_defaultStyle[GeoDataPlacemark::HighwayService] = createHighwayStyle("#ffffff", "#bbbbbb", osmFont, "000000", 1, 6); m_defaultStyle[GeoDataPlacemark::HighwayResidential] = createHighwayStyle("#ffffff", "#bbbbbb", osmFont, "000000", 3, 6); m_defaultStyle[GeoDataPlacemark::HighwayLivingStreet] = createHighwayStyle("#ffffff", "#bbbbbb", osmFont, "000000", 3, 6); m_defaultStyle[GeoDataPlacemark::HighwayRoad] = createHighwayStyle("#dddddd", "#bbbbbb", osmFont, "000000", 3, 6); m_defaultStyle[GeoDataPlacemark::HighwayUnclassified] = createHighwayStyle("#ffffff", "#bbbbbb", osmFont, "000000", 3, 6); m_defaultStyle[GeoDataPlacemark::HighwayTertiary] = createHighwayStyle("#ffffff", "#8f8f8f", osmFont, "000000", 6, 6); m_defaultStyle[GeoDataPlacemark::HighwayTertiaryLink] = createHighwayStyle("#ffffff", "#8f8f8f", osmFont, "000000", 6, 6); m_defaultStyle[GeoDataPlacemark::HighwaySecondary] = createHighwayStyle("#f7fabf", "#707d05", osmFont, "000000", 6, 6); m_defaultStyle[GeoDataPlacemark::HighwaySecondaryLink] = createHighwayStyle("#f7fabf", "#707d05", osmFont, "000000", 6, 6); m_defaultStyle[GeoDataPlacemark::HighwayPrimary] = createHighwayStyle("#fcd6a4", "#a06b00", osmFont, "000000", 9, 6); m_defaultStyle[GeoDataPlacemark::HighwayPrimaryLink] = createHighwayStyle("#fcd6a4", "#a06b00", osmFont, "000000", 6, 6); m_defaultStyle[GeoDataPlacemark::HighwayRaceway] = createHighwayStyle("#ffc0cb", "#ffc0cb", osmFont, "000000", 1, 5); m_defaultStyle[GeoDataPlacemark::HighwayTrunk] = createHighwayStyle("#f9b29c", "#c84e2f", osmFont, "000000", 9, 6); m_defaultStyle[GeoDataPlacemark::HighwayTrunkLink] = createHighwayStyle("#f9b29c", "#c84e2f", osmFont, "000000", 9, 6); m_defaultStyle[GeoDataPlacemark::HighwayMotorway] = createHighwayStyle("#e892a2", "#dc2a67", osmFont, "000000", 9, 10); m_defaultStyle[GeoDataPlacemark::HighwayMotorwayLink] = createHighwayStyle("#e892a2", "#dc2a67", osmFont, "000000", 9, 10); m_defaultStyle[GeoDataPlacemark::HighwayCorridor] = createHighwayStyle("#ffffff", "#bbbbbb", osmFont, "000000", 1, 3); m_defaultStyle[GeoDataPlacemark::TransportAirportRunway] = createHighwayStyle("#bbbbcc", "#bbbbcc", osmFont, "000000", 0, 1, Qt::NoPen); m_defaultStyle[GeoDataPlacemark::TransportAirportTaxiway] = createHighwayStyle("#bbbbcc", "#bbbbcc", osmFont, "000000", 0, 1, Qt::NoPen); m_defaultStyle[GeoDataPlacemark::TransportAirportApron] = createWayStyle("#e9d1ff", Qt::transparent, true, false); m_defaultStyle[GeoDataPlacemark::TransportSpeedCamera] = createOsmPOIStyle(osmFont, "individual/speedcamera"); m_defaultStyle[GeoDataPlacemark::NaturalWater] = createStyle(4, 0, waterColor, waterColor, true, false, Qt::SolidPattern, Qt::SolidLine, Qt::RoundCap, false, QVector< qreal >(), osmFont, waterColor.darker(150)); m_defaultStyle[GeoDataPlacemark::WaterwayRiver] = createStyle(4, 0, waterColor, waterColor, true, false, Qt::SolidPattern, Qt::SolidLine, Qt::RoundCap, false, QVector< qreal >(), osmFont, waterColor.darker(150)); m_defaultStyle[GeoDataPlacemark::WaterwayCanal] = m_defaultStyle[GeoDataPlacemark::WaterwayRiver]; m_defaultStyle[GeoDataPlacemark::WaterwayDitch] = m_defaultStyle[GeoDataPlacemark::WaterwayRiver]; m_defaultStyle[GeoDataPlacemark::WaterwayDrain] = m_defaultStyle[GeoDataPlacemark::WaterwayRiver]; m_defaultStyle[GeoDataPlacemark::WaterwayStream] = m_defaultStyle[GeoDataPlacemark::WaterwayRiver]; m_defaultStyle[GeoDataPlacemark::WaterwayWeir] = createStyle(4, 0, "#ffffff", "#87939b", true, false, Qt::SolidPattern, Qt::DotLine, Qt::RoundCap, true, QVector< qreal >(), osmFont, waterColor.darker(150)); m_defaultStyle[GeoDataPlacemark::CrossingIsland] = createOsmPOIStyle(osmFont, "transportation/zebra_crossing", transportationColor); m_defaultStyle[GeoDataPlacemark::CrossingIsland]->iconStyle().setScale(0.75); m_defaultStyle[GeoDataPlacemark::CrossingRailway] = createOsmPOIStyle(osmFont, "transportation/railway_crossing", transportationColor); m_defaultStyle[GeoDataPlacemark::CrossingRailway]->iconStyle().setScale(0.5); m_defaultStyle[GeoDataPlacemark::CrossingSignals] = createOsmPOIStyle(osmFont, "transportation/traffic_light_crossing", transportationColor); m_defaultStyle[GeoDataPlacemark::CrossingSignals]->iconStyle().setScale(0.75); m_defaultStyle[GeoDataPlacemark::CrossingZebra] = createOsmPOIStyle(osmFont, "transportation/zebra_crossing", transportationColor); m_defaultStyle[GeoDataPlacemark::CrossingZebra]->iconStyle().setScale(0.75); m_defaultStyle[GeoDataPlacemark::NaturalReef] = createStyle(5.5, 0, "#36677c", "#36677c", true, false, Qt::Dense7Pattern, Qt::DotLine, Qt::RoundCap, false, QVector< qreal >(), osmFont, waterColor.darker(150)); m_defaultStyle[GeoDataPlacemark::AmenityGraveyard] = createWayStyle("#AACBAF", "#AACBAF", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/grave_yard_generic.png")); m_defaultStyle[GeoDataPlacemark::NaturalWood] = createWayStyle("#8DC46C", "#8DC46C", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/forest.png")); m_defaultStyle[GeoDataPlacemark::NaturalBeach] = createWayStyle("#FFF1BA", "#FFF1BA", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/beach.png")); m_defaultStyle[GeoDataPlacemark::NaturalWetland] = createWayStyle("#DDECEC", "#DDECEC", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/wetland.png")); m_defaultStyle[GeoDataPlacemark::NaturalGlacier] = createWayStyle("#DDECEC", "#DDECEC", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/glacier.png")); m_defaultStyle[GeoDataPlacemark::NaturalIceShelf] = createWayStyle("#8ebebe", "#8ebebe", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/glacier.png")); m_defaultStyle[GeoDataPlacemark::NaturalScrub] = createWayStyle("#B5E3B5", "#B5E3B5", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/scrub.png")); m_defaultStyle[GeoDataPlacemark::NaturalCliff] = createWayStyle(Qt::transparent, Qt::transparent, true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/cliff2.png")); m_defaultStyle[GeoDataPlacemark::NaturalCave] = createOsmPOIStyle(osmFont, "amenities/cave", amenityColor); m_defaultStyle[GeoDataPlacemark::NaturalHeath] = createWayStyle("#d6d99f", QColor("#d6d99f").darker(150), true, false); m_defaultStyle[GeoDataPlacemark::LeisureGolfCourse] = createOsmPOIAreaStyle(osmFont, "leisure/golf", "#39ac39", "#b5e3b5", QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::LeisureMinigolfCourse] = createOsmPOIAreaStyle(osmFont, "leisure/miniature_golf", "#39ac39", "#b5e3b5", QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::LeisureMarina] = createOsmPOIStyle(osmFont, QString(), QColor("#95abd5"), QColor("#aec8d1"), QColor("#95abd5").darker(150)); m_defaultStyle[GeoDataPlacemark::LeisurePark] = createWayStyle(QColor("#c8facc"), QColor("#c8facc").darker(150), true, true); m_defaultStyle[GeoDataPlacemark::LeisurePlayground] = createOsmPOIAreaStyle(osmFont, "amenity/playground.16", amenityColor, "#CCFFF1", "#BDFFED"); m_defaultStyle[GeoDataPlacemark::LeisurePitch] = createWayStyle("#8ad3af", QColor("#8ad3af").darker(150), true, true); m_defaultStyle[GeoDataPlacemark::LeisureSportsCentre] = createWayStyle("#33cc99", QColor("#33cc99").darker(150), true, true); m_defaultStyle[GeoDataPlacemark::LeisureStadium] = createWayStyle("#33cc99", QColor("#33cc99").darker(150), true, true); m_defaultStyle[GeoDataPlacemark::LeisureTrack] = createWayStyle("#74dcba", QColor("#74dcba").darker(150), true, true); m_defaultStyle[GeoDataPlacemark::LeisureSwimmingPool] = createWayStyle(waterColor, waterColor.darker(150), true, true); m_defaultStyle[GeoDataPlacemark::LanduseAllotments] = createWayStyle("#E4C6AA", "#E4C6AA", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/allotments.png")); m_defaultStyle[GeoDataPlacemark::LanduseBasin] = createWayStyle(QColor(0xB5, 0xD0, 0xD0, 0x80), QColor(0xB5, 0xD0, 0xD0)); m_defaultStyle[GeoDataPlacemark::LanduseCemetery] = createWayStyle("#AACBAF", "#AACBAF", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/grave_yard_generic.png")); m_defaultStyle[GeoDataPlacemark::LanduseCommercial] = createWayStyle("#F2DAD9", "#D1B2B0", true, true); m_defaultStyle[GeoDataPlacemark::LanduseConstruction] = createWayStyle("#b6b592", "#b6b592", true, false); m_defaultStyle[GeoDataPlacemark::LanduseFarmland] = createWayStyle("#EDDDC9", "#C8B69E", true, true); m_defaultStyle[GeoDataPlacemark::LanduseFarmyard] = createWayStyle("#EFD6B5", "#D1B48C", true, true); m_defaultStyle[GeoDataPlacemark::LanduseGarages] = createWayStyle("#E0DDCD", "#E0DDCD", true, false); m_defaultStyle[GeoDataPlacemark::LanduseGrass] = createWayStyle("#A8C8A5", "#A8C8A5", true, false); m_defaultStyle[GeoDataPlacemark::LanduseIndustrial] = createWayStyle("#DED0D5", "#DED0D5", true, false); m_defaultStyle[GeoDataPlacemark::LanduseLandfill] = createWayStyle("#b6b592", "#b6b592", true, false); m_defaultStyle[GeoDataPlacemark::LanduseMeadow] = createWayStyle("#cdebb0", "#cdebb0", true, false); m_defaultStyle[GeoDataPlacemark::LanduseMilitary] = createWayStyle("#F3D8D2", "#F3D8D2", true, true, Qt::BDiagPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/military_red_hatch.png")); m_defaultStyle[GeoDataPlacemark::LanduseQuarry] = createWayStyle("#C4C2C2", "#C4C2C2", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/quarry.png")); m_defaultStyle[GeoDataPlacemark::LanduseRailway] = createWayStyle("#DED0D5", "#DED0D5", true, false); m_defaultStyle[GeoDataPlacemark::LanduseReservoir] = createWayStyle(waterColor, waterColor, true, false); m_defaultStyle[GeoDataPlacemark::LanduseResidential] = createWayStyle("#DCDCDC", "#DCDCDC", true, false); m_defaultStyle[GeoDataPlacemark::LanduseRetail] = createWayStyle("#FFD6D1", "#D99C95", true, true); m_defaultStyle[GeoDataPlacemark::LanduseOrchard] = createWayStyle("#AEDFA3", "#AEDFA3", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/orchard.png")); m_defaultStyle[GeoDataPlacemark::LanduseVineyard] = createWayStyle("#AEDFA3", "#AEDFA3", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/vineyard.png")); m_defaultStyle[GeoDataPlacemark::MilitaryDangerArea] = createWayStyle("#FFC0CB", "#FFC0CB", true, false, Qt::SolidPattern, MarbleDirs::path("bitmaps/osmcarto/patterns/danger.png")); m_defaultStyle[GeoDataPlacemark::RailwayRail] = createStyle(2.0, 1.435, "#706E70", "#EEEEEE", true, true, Qt::SolidPattern, Qt::CustomDashLine, Qt::FlatCap, true, QVector< qreal >() << 2 << 3, osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::RailwayNarrowGauge] = createStyle(2.0, 1.0, "#706E70", "#EEEEEE", true, true, Qt::SolidPattern, Qt::CustomDashLine, Qt::FlatCap, true, QVector< qreal >() << 2 << 3, osmFont, QColor(Qt::transparent)); // FIXME: the tram is currently being rendered as a polygon. m_defaultStyle[GeoDataPlacemark::RailwayTram] = createStyle(2.0, 1.435, "#706E70", "#B7B6B7", false, true, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::RailwayLightRail] = createStyle(2.0, 1.435, "#706E70", "#706E70", false, true, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::RailwayAbandoned] = createStyle(2.0, 1.435, Qt::transparent, "#706E70", false, false, Qt::SolidPattern, Qt::DotLine, Qt::FlatCap, false, QVector(), osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::RailwaySubway] = createStyle(2.0, 1.435, "#706E70", "#EEEEEE", false, true, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::RailwayPreserved] = createStyle(2.0, 1.435, "#EEEEEE", "#706E70", true, true, Qt::SolidPattern, Qt::DotLine, Qt::FlatCap, true, QVector(), osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::RailwayMiniature] = createStyle(2.0, 1.435, "#706E70", "#EEEEEE", false, true, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::RailwayConstruction] = createStyle(2.0, 1.435, "#EEEEEE", "#706E70", true, true, Qt::SolidPattern, Qt::DotLine, Qt::FlatCap, true, QVector(), osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::RailwayMonorail] = createStyle(2.0, 1.435, "#706E70", "#EEEEEE", false, true, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::RailwayFunicular] = createStyle(2.0, 1.435, "#706E70", "#EEEEEE", false, true, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont, QColor(Qt::transparent)); m_defaultStyle[GeoDataPlacemark::Landmass] = createWayStyle("#F1EEE8", "#F1EEE8", true, false); m_defaultStyle[GeoDataPlacemark::UrbanArea] = createWayStyle("#E6E3DD", "#E6E3DD", true, false); m_defaultStyle[GeoDataPlacemark::InternationalDateLine] = createStyle(1.0, 0.0, "#000000", "#000000", false, true, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont); m_defaultStyle[GeoDataPlacemark::Bathymetry] = createWayStyle("#a5c9c9", "#a5c9c9", true, false); m_defaultStyle[GeoDataPlacemark::AerialwayStation] = createOsmPOIStyle(osmFont, "individual/railway_station", transportationColor); m_defaultStyle[GeoDataPlacemark::AerialwayStation]->iconStyle().setScale(0.33f); m_defaultStyle[GeoDataPlacemark::AerialwayPylon] = createOsmPOIStyle(osmFont, "individual/pylon", QColor("#dddddd")); m_defaultStyle[GeoDataPlacemark::AerialwayPylon]->iconStyle().setScale(0.33f); m_defaultStyle[GeoDataPlacemark::AerialwayCableCar] = createIconWayStyle("#bbbbbb", osmFont, transportationColor, 1.0, QStringLiteral("svg/thenounproject/transportation-583813-cable-car.svg")); m_defaultStyle[GeoDataPlacemark::AerialwayGondola] = createIconWayStyle("#bbbbbb", osmFont, transportationColor, 1.0, QStringLiteral("svg/thenounproject/transportation-21636-gondola.svg")); m_defaultStyle[GeoDataPlacemark::AerialwayChairLift] = createIconWayStyle("#bbbbbb", osmFont, transportationColor, 1.0, QStringLiteral("svg/thenounproject/transportation-231-chair-lift.svg")); m_defaultStyle[GeoDataPlacemark::AerialwayMixedLift] = createIconWayStyle("#bbbbbb", osmFont, transportationColor); m_defaultStyle[GeoDataPlacemark::AerialwayDragLift] = createIconWayStyle("#bbbbbb", osmFont, transportationColor, 1.0, QStringLiteral("svg/thenounproject/transportation-8803-platter-lift.svg")); m_defaultStyle[GeoDataPlacemark::AerialwayTBar] = createIconWayStyle("#bbbbbb", osmFont, transportationColor, 1.0, QStringLiteral("svg/thenounproject/transportation-8803-platter-lift.svg")); m_defaultStyle[GeoDataPlacemark::AerialwayJBar] = createIconWayStyle("#bbbbbb", osmFont, transportationColor, 1.0, QStringLiteral("svg/thenounproject/transportation-8803-platter-lift.svg")); m_defaultStyle[GeoDataPlacemark::AerialwayPlatter] = createIconWayStyle("#bbbbbb", osmFont, transportationColor, 1.0, QStringLiteral("svg/thenounproject/transportation-8803-platter-lift.svg")); m_defaultStyle[GeoDataPlacemark::AerialwayRopeTow] = createIconWayStyle("#bbbbbb", osmFont, transportationColor); m_defaultStyle[GeoDataPlacemark::AerialwayMagicCarpet] = createIconWayStyle("#bbbbbb", osmFont, transportationColor); m_defaultStyle[GeoDataPlacemark::AerialwayZipLine] = createIconWayStyle("#bbbbbb", osmFont, transportationColor); m_defaultStyle[GeoDataPlacemark::AerialwayGoods] = createIconWayStyle("#bbbbbb", osmFont, transportationColor); m_defaultStyle[GeoDataPlacemark::PisteDownhill] = createStyle(9, 0.0, "#dddddd", Qt::transparent, true, false, Qt::SolidPattern, Qt::SolidLine, Qt::RoundCap, false, QVector< qreal >(), osmFont, Qt::transparent); m_defaultStyle[GeoDataPlacemark::PisteNordic] = createStyle(3, 0.0, "#fffafa", "#006666", true, false, Qt::SolidPattern, Qt::SolidLine, Qt::RoundCap, false, QVector< qreal >(), osmFont, Qt::transparent, MarbleDirs::path("bitmaps/osmcarto/patterns/ice.png")); m_defaultStyle[GeoDataPlacemark::PisteSkitour] = m_defaultStyle[GeoDataPlacemark::PisteNordic]; m_defaultStyle[GeoDataPlacemark::PisteSled] = m_defaultStyle[GeoDataPlacemark::PisteNordic]; m_defaultStyle[GeoDataPlacemark::PisteHike] = m_defaultStyle[GeoDataPlacemark::PisteNordic]; m_defaultStyle[GeoDataPlacemark::PisteSleigh] = m_defaultStyle[GeoDataPlacemark::PisteNordic]; m_defaultStyle[GeoDataPlacemark::PisteIceSkate] = m_defaultStyle[GeoDataPlacemark::PisteNordic]; m_defaultStyle[GeoDataPlacemark::PisteSnowPark] = m_defaultStyle[GeoDataPlacemark::PisteNordic]; m_defaultStyle[GeoDataPlacemark::PistePlayground] = m_defaultStyle[GeoDataPlacemark::PisteNordic]; m_defaultStyle[GeoDataPlacemark::PisteSkiJump] = createIconWayStyle("#bbbbbb", osmFont, transportationColor, 1.0, QStringLiteral("svg/thenounproject/sports-245-ski-jump.svg")); m_defaultStyle[GeoDataPlacemark::AdminLevel1] = createStyle(0.0, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::CustomDashLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel2] = createStyle(2.0, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel3] = createStyle(1.8, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::DashLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel4] = createStyle(1.5, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::DotLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel5] = createStyle(1.25, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::DashDotDotLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel6] = createStyle(1, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::DashDotLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel7] = createStyle(1, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::DashLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel8] = createStyle(1, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::DashLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel9] = createStyle(1.5, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::DotLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel10] = createStyle(1.5, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::DotLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::AdminLevel11] = createStyle(1.5, 0.0, "#DF9CCF", "#DF9CCF", false, true, Qt::SolidPattern, Qt::DotLine, Qt::FlatCap, false, QVector< qreal >() << 0.3 << 0.3, osmFont); m_defaultStyle[GeoDataPlacemark::BoundaryMaritime] = createStyle(2.0, 0.0, "#88b3bf", "#88b3bf", false, true, Qt::SolidPattern, Qt::SolidLine, Qt::FlatCap, false, QVector(), osmFont); m_defaultStyle[GeoDataPlacemark::Satellite] = GeoDataStyle::Ptr(new GeoDataStyle(MarbleDirs::path("bitmaps/satellite.png"), QFont(defaultFamily, defaultSize, 50, false), defaultLabelColor)); QFont tmp; // Fonts for areas ... tmp = m_defaultStyle[GeoDataPlacemark::Continent]->labelStyle().font(); tmp.setLetterSpacing(QFont::AbsoluteSpacing, 2); tmp.setCapitalization(QFont::AllUppercase); tmp.setBold(true); m_defaultStyle[GeoDataPlacemark::Continent]->labelStyle().setFont(tmp); // Fonts for areas ... tmp = m_defaultStyle[GeoDataPlacemark::Mare]->labelStyle().font(); tmp.setLetterSpacing(QFont::AbsoluteSpacing, 2); tmp.setCapitalization(QFont::AllUppercase); tmp.setBold(true); m_defaultStyle[GeoDataPlacemark::Mare]->labelStyle().setFont(tmp); // Now we need to underline the capitals ... tmp = m_defaultStyle[GeoDataPlacemark::SmallNationCapital]->labelStyle().font(); tmp.setUnderline(true); m_defaultStyle[GeoDataPlacemark::SmallNationCapital]->labelStyle().setFont(tmp); tmp = m_defaultStyle[GeoDataPlacemark::MediumNationCapital]->labelStyle().font(); tmp.setUnderline(true); m_defaultStyle[GeoDataPlacemark::MediumNationCapital]->labelStyle().setFont(tmp); tmp = m_defaultStyle[GeoDataPlacemark::BigNationCapital]->labelStyle().font(); tmp.setUnderline(true); m_defaultStyle[GeoDataPlacemark::BigNationCapital]->labelStyle().setFont(tmp); tmp = m_defaultStyle[GeoDataPlacemark::LargeNationCapital]->labelStyle().font(); tmp.setUnderline(true); m_defaultStyle[GeoDataPlacemark::LargeNationCapital]->labelStyle().setFont(tmp); // Buildings m_defaultStyle[GeoDataPlacemark::Building] = createStyle(1, 0, buildingColor, buildingColor.darker(), true, true, Qt::SolidPattern, Qt::SolidLine, Qt::RoundCap, false, QVector(), osmFont); for (int i = 0; i < GeoDataPlacemark::LastIndex; ++i) { if (m_defaultStyle[i] && !m_defaultStyle[i]->iconStyle().iconPath().isEmpty()) { auto const category = GeoDataPlacemark::GeoDataVisualCategory(i); m_buildingStyles[category] = GeoDataStyle::Ptr(new GeoDataStyle(*m_defaultStyle[GeoDataPlacemark::Building])); m_buildingStyles[category]->iconStyle() = m_defaultStyle[i]->iconStyle(); m_buildingStyles[category]->labelStyle() = m_defaultStyle[i]->labelStyle(); } } } QString StyleBuilder::Private::createPaintLayerItem(const QString &itemType, GeoDataPlacemark::GeoDataVisualCategory visualCategory, const QString &subType) { QString const category = visualCategoryName(visualCategory); if (subType.isEmpty()) { return itemType + QLatin1Char('/') + category; } else { return itemType + QLatin1Char('/') + category + QLatin1Char('/') + subType; } } void StyleBuilder::Private::initializeOsmVisualCategories() { // Only initialize the map once if (!s_visualCategories.isEmpty()) { return; } s_visualCategories[OsmTag("admin_level", "1")] = GeoDataPlacemark::AdminLevel1; s_visualCategories[OsmTag("admin_level", "2")] = GeoDataPlacemark::AdminLevel2; s_visualCategories[OsmTag("admin_level", "3")] = GeoDataPlacemark::AdminLevel3; s_visualCategories[OsmTag("admin_level", "4")] = GeoDataPlacemark::AdminLevel4; s_visualCategories[OsmTag("admin_level", "5")] = GeoDataPlacemark::AdminLevel5; s_visualCategories[OsmTag("admin_level", "6")] = GeoDataPlacemark::AdminLevel6; s_visualCategories[OsmTag("admin_level", "7")] = GeoDataPlacemark::AdminLevel7; s_visualCategories[OsmTag("admin_level", "8")] = GeoDataPlacemark::AdminLevel8; s_visualCategories[OsmTag("admin_level", "9")] = GeoDataPlacemark::AdminLevel9; s_visualCategories[OsmTag("admin_level", "10")] = GeoDataPlacemark::AdminLevel10; s_visualCategories[OsmTag("admin_level", "11")] = GeoDataPlacemark::AdminLevel11; s_visualCategories[OsmTag("boundary", "maritime")] = GeoDataPlacemark::BoundaryMaritime; s_visualCategories[OsmTag("amenity", "restaurant")] = GeoDataPlacemark::FoodRestaurant; s_visualCategories[OsmTag("amenity", "fast_food")] = GeoDataPlacemark::FoodFastFood; s_visualCategories[OsmTag("amenity", "pub")] = GeoDataPlacemark::FoodPub; s_visualCategories[OsmTag("amenity", "bar")] = GeoDataPlacemark::FoodBar; s_visualCategories[OsmTag("amenity", "cafe")] = GeoDataPlacemark::FoodCafe; s_visualCategories[OsmTag("amenity", "biergarten")] = GeoDataPlacemark::FoodBiergarten; s_visualCategories[OsmTag("amenity", "college")] = GeoDataPlacemark::EducationCollege; s_visualCategories[OsmTag("amenity", "school")] = GeoDataPlacemark::EducationSchool; s_visualCategories[OsmTag("amenity", "university")] = GeoDataPlacemark::EducationUniversity; s_visualCategories[OsmTag("amenity", "childcare")] = GeoDataPlacemark::AmenityKindergarten; s_visualCategories[OsmTag("amenity", "kindergarten")] = GeoDataPlacemark::AmenityKindergarten; s_visualCategories[OsmTag("amenity", "library")] = GeoDataPlacemark::AmenityLibrary; s_visualCategories[OsmTag("amenity", "bus_station")] = GeoDataPlacemark::TransportBusStation; s_visualCategories[OsmTag("amenity", "car_sharing")] = GeoDataPlacemark::TransportCarShare; s_visualCategories[OsmTag("amenity", "fuel")] = GeoDataPlacemark::TransportFuel; s_visualCategories[OsmTag("amenity", "parking")] = GeoDataPlacemark::TransportParking; s_visualCategories[OsmTag("amenity", "parking_space")] = GeoDataPlacemark::TransportParkingSpace; s_visualCategories[OsmTag("amenity", "atm")] = GeoDataPlacemark::MoneyAtm; s_visualCategories[OsmTag("amenity", "bank")] = GeoDataPlacemark::MoneyBank; s_visualCategories[OsmTag("historic", "archaeological_site")] = GeoDataPlacemark::HistoricArchaeologicalSite; s_visualCategories[OsmTag("historic", "castle")] = GeoDataPlacemark::HistoricCastle; s_visualCategories[OsmTag("historic", "fort")] = GeoDataPlacemark::HistoricCastle; s_visualCategories[OsmTag("historic", "memorial")] = GeoDataPlacemark::HistoricMemorial; s_visualCategories[OsmTag("historic", "monument")] = GeoDataPlacemark::HistoricMonument; s_visualCategories[OsmTag("historic", "ruins")] = GeoDataPlacemark::HistoricRuins; s_visualCategories[OsmTag("amenity", "bench")] = GeoDataPlacemark::AmenityBench; s_visualCategories[OsmTag("amenity", "car_wash")] = GeoDataPlacemark::AmenityCarWash; s_visualCategories[OsmTag("amenity", "charging_station")] = GeoDataPlacemark::AmenityChargingStation; s_visualCategories[OsmTag("amenity", "cinema")] = GeoDataPlacemark::AmenityCinema; s_visualCategories[OsmTag("amenity", "community_centre")] = GeoDataPlacemark::AmenityCommunityCentre; s_visualCategories[OsmTag("amenity", "courthouse")] = GeoDataPlacemark::AmenityCourtHouse; s_visualCategories[OsmTag("amenity", "drinking_water")] = GeoDataPlacemark::AmenityDrinkingWater; s_visualCategories[OsmTag("amenity", "embassy")] = GeoDataPlacemark::AmenityEmbassy; s_visualCategories[OsmTag("amenity", "fire_station")] = GeoDataPlacemark::AmenityFireStation; s_visualCategories[OsmTag("amenity", "fountain")] = GeoDataPlacemark::AmenityFountain; s_visualCategories[OsmTag("amenity", "graveyard")] = GeoDataPlacemark::AmenityGraveyard; s_visualCategories[OsmTag("amenity", "hunting_stand")] = GeoDataPlacemark::AmenityHuntingStand; s_visualCategories[OsmTag("amenity", "nightclub")] = GeoDataPlacemark::AmenityNightClub; s_visualCategories[OsmTag("amenity", "police")] = GeoDataPlacemark::AmenityPolice; s_visualCategories[OsmTag("amenity", "post_box")] = GeoDataPlacemark::AmenityPostBox; s_visualCategories[OsmTag("amenity", "post_office")] = GeoDataPlacemark::AmenityPostOffice; s_visualCategories[OsmTag("amenity", "prison")] = GeoDataPlacemark::AmenityPrison; s_visualCategories[OsmTag("amenity", "recycling")] = GeoDataPlacemark::AmenityRecycling; s_visualCategories[OsmTag("amenity", "shelter")] = GeoDataPlacemark::AmenityShelter; s_visualCategories[OsmTag("amenity", "social_facility")] = GeoDataPlacemark::AmenitySocialFacility; s_visualCategories[OsmTag("amenity", "telephone")] = GeoDataPlacemark::AmenityTelephone; s_visualCategories[OsmTag("amenity", "theatre")] = GeoDataPlacemark::AmenityTheatre; s_visualCategories[OsmTag("amenity", "toilets")] = GeoDataPlacemark::AmenityToilets; s_visualCategories[OsmTag("amenity", "townhall")] = GeoDataPlacemark::AmenityTownHall; s_visualCategories[OsmTag("amenity", "waste_basket")] = GeoDataPlacemark::AmenityWasteBasket; s_visualCategories[OsmTag("emergency", "phone")] = GeoDataPlacemark::AmenityEmergencyPhone; s_visualCategories[OsmTag("amenity", "mountain_rescue")] = GeoDataPlacemark::AmenityMountainRescue; s_visualCategories[OsmTag("amenity", "dentist")] = GeoDataPlacemark::HealthDentist; s_visualCategories[OsmTag("amenity", "doctors")] = GeoDataPlacemark::HealthDoctors; s_visualCategories[OsmTag("amenity", "hospital")] = GeoDataPlacemark::HealthHospital; s_visualCategories[OsmTag("amenity", "pharmacy")] = GeoDataPlacemark::HealthPharmacy; s_visualCategories[OsmTag("amenity", "veterinary")] = GeoDataPlacemark::HealthVeterinary; s_visualCategories[OsmTag("amenity", "place_of_worship")] = GeoDataPlacemark::ReligionPlaceOfWorship; s_visualCategories[OsmTag("tourism", "information")] = GeoDataPlacemark::TourismInformation; s_visualCategories[OsmTag("natural", "cave_entrance")] = GeoDataPlacemark::NaturalCave; s_visualCategories[OsmTag("natural", "peak")] = GeoDataPlacemark::NaturalPeak; s_visualCategories[OsmTag("natural", "tree")] = GeoDataPlacemark::NaturalTree; s_visualCategories[OsmTag("natural", "volcano")] = GeoDataPlacemark::NaturalVolcano; s_visualCategories[OsmTag("shop", "alcohol")] = GeoDataPlacemark::ShopAlcohol; s_visualCategories[OsmTag("shop", "art")] = GeoDataPlacemark::ShopArt; s_visualCategories[OsmTag("shop", "bag")] = GeoDataPlacemark::ShopBag; s_visualCategories[OsmTag("shop", "bakery")] = GeoDataPlacemark::ShopBakery; s_visualCategories[OsmTag("shop", "beauty")] = GeoDataPlacemark::ShopBeauty; s_visualCategories[OsmTag("shop", "beverages")] = GeoDataPlacemark::ShopBeverages; s_visualCategories[OsmTag("shop", "bicycle")] = GeoDataPlacemark::ShopBicycle; s_visualCategories[OsmTag("shop", "books")] = GeoDataPlacemark::ShopBook; s_visualCategories[OsmTag("shop", "butcher")] = GeoDataPlacemark::ShopButcher; s_visualCategories[OsmTag("shop", "car")] = GeoDataPlacemark::ShopCar; s_visualCategories[OsmTag("shop", "car_parts")] = GeoDataPlacemark::ShopCarParts; s_visualCategories[OsmTag("shop", "car_repair")] = GeoDataPlacemark::ShopCarRepair; s_visualCategories[OsmTag("shop", "chemist")] = GeoDataPlacemark::ShopChemist; s_visualCategories[OsmTag("shop", "clothes")] = GeoDataPlacemark::ShopClothes; s_visualCategories[OsmTag("shop", "confectionery")] = GeoDataPlacemark::ShopConfectionery; s_visualCategories[OsmTag("shop", "convenience")] = GeoDataPlacemark::ShopConvenience; s_visualCategories[OsmTag("shop", "copy")] = GeoDataPlacemark::ShopCopy; s_visualCategories[OsmTag("shop", "cosmetics")] = GeoDataPlacemark::ShopCosmetics; s_visualCategories[OsmTag("shop", "deli")] = GeoDataPlacemark::ShopDeli; s_visualCategories[OsmTag("shop", "department_store")] = GeoDataPlacemark::ShopDepartmentStore; s_visualCategories[OsmTag("shop", "doityourself")] = GeoDataPlacemark::ShopDoitYourself; s_visualCategories[OsmTag("shop", "electronics")] = GeoDataPlacemark::ShopElectronics; s_visualCategories[OsmTag("shop", "fashion")] = GeoDataPlacemark::ShopFashion; s_visualCategories[OsmTag("shop", "florist")] = GeoDataPlacemark::ShopFlorist; s_visualCategories[OsmTag("shop", "furniture")] = GeoDataPlacemark::ShopFurniture; s_visualCategories[OsmTag("shop", "gift")] = GeoDataPlacemark::ShopGift; s_visualCategories[OsmTag("shop", "greengrocer")] = GeoDataPlacemark::ShopGreengrocer; s_visualCategories[OsmTag("shop", "hairdresser")] = GeoDataPlacemark::ShopHairdresser; s_visualCategories[OsmTag("shop", "hardware")] = GeoDataPlacemark::ShopHardware; s_visualCategories[OsmTag("shop", "hifi")] = GeoDataPlacemark::ShopHifi; s_visualCategories[OsmTag("shop", "jewelry")] = GeoDataPlacemark::ShopJewelry; s_visualCategories[OsmTag("shop", "kiosk")] = GeoDataPlacemark::ShopKiosk; s_visualCategories[OsmTag("shop", "laundry")] = GeoDataPlacemark::ShopLaundry; s_visualCategories[OsmTag("shop", "mobile_phone")] = GeoDataPlacemark::ShopMobilePhone; s_visualCategories[OsmTag("shop", "motorcycle")] = GeoDataPlacemark::ShopMotorcycle; s_visualCategories[OsmTag("shop", "musical_instrument")] = GeoDataPlacemark::ShopMusicalInstrument; s_visualCategories[OsmTag("shop", "optician")] = GeoDataPlacemark::ShopOptician; s_visualCategories[OsmTag("shop", "outdoor")] = GeoDataPlacemark::ShopOutdoor; s_visualCategories[OsmTag("shop", "perfumery")] = GeoDataPlacemark::ShopPerfumery; s_visualCategories[OsmTag("shop", "pet")] = GeoDataPlacemark::ShopPet; s_visualCategories[OsmTag("shop", "photo")] = GeoDataPlacemark::ShopPhoto; s_visualCategories[OsmTag("shop", "seafood")] = GeoDataPlacemark::ShopSeafood; s_visualCategories[OsmTag("shop", "shoes")] = GeoDataPlacemark::ShopShoes; s_visualCategories[OsmTag("shop", "sports")] = GeoDataPlacemark::ShopSports; s_visualCategories[OsmTag("shop", "stationery")] = GeoDataPlacemark::ShopStationery; s_visualCategories[OsmTag("shop", "supermarket")] = GeoDataPlacemark::ShopSupermarket; s_visualCategories[OsmTag("shop", "tea")] = GeoDataPlacemark::ShopTea; s_visualCategories[OsmTag("shop", "tobacco")] = GeoDataPlacemark::ShopTobacco; s_visualCategories[OsmTag("shop", "toys")] = GeoDataPlacemark::ShopToys; s_visualCategories[OsmTag("shop", "travel_agency")] = GeoDataPlacemark::ShopTravelAgency; s_visualCategories[OsmTag("shop", "variety_store")] = GeoDataPlacemark::ShopVarietyStore; // Default for all other shops for (const QString &value: shopValues()) { s_visualCategories[OsmTag("shop", value)] = GeoDataPlacemark::Shop; } s_visualCategories[OsmTag("man_made", "bridge")] = GeoDataPlacemark::ManmadeBridge; s_visualCategories[OsmTag("man_made", "lighthouse")] = GeoDataPlacemark::ManmadeLighthouse; s_visualCategories[OsmTag("man_made", "pier")] = GeoDataPlacemark::ManmadePier; s_visualCategories[OsmTag("man_made", "water_tower")] = GeoDataPlacemark::ManmadeWaterTower; s_visualCategories[OsmTag("man_made", "windmill")] = GeoDataPlacemark::ManmadeWindMill; s_visualCategories[OsmTag("religion", "")] = GeoDataPlacemark::ReligionPlaceOfWorship; s_visualCategories[OsmTag("religion", "bahai")] = GeoDataPlacemark::ReligionBahai; s_visualCategories[OsmTag("religion", "buddhist")] = GeoDataPlacemark::ReligionBuddhist; s_visualCategories[OsmTag("religion", "christian")] = GeoDataPlacemark::ReligionChristian; s_visualCategories[OsmTag("religion", "hindu")] = GeoDataPlacemark::ReligionHindu; s_visualCategories[OsmTag("religion", "jain")] = GeoDataPlacemark::ReligionJain; s_visualCategories[OsmTag("religion", "jewish")] = GeoDataPlacemark::ReligionJewish; s_visualCategories[OsmTag("religion", "muslim")] = GeoDataPlacemark::ReligionMuslim; s_visualCategories[OsmTag("religion", "shinto")] = GeoDataPlacemark::ReligionShinto; s_visualCategories[OsmTag("religion", "sikh")] = GeoDataPlacemark::ReligionSikh; s_visualCategories[OsmTag("tourism", "camp_site")] = GeoDataPlacemark::AccomodationCamping; s_visualCategories[OsmTag("tourism", "guest_house")] = GeoDataPlacemark::AccomodationGuestHouse; s_visualCategories[OsmTag("tourism", "hostel")] = GeoDataPlacemark::AccomodationHostel; s_visualCategories[OsmTag("tourism", "hotel")] = GeoDataPlacemark::AccomodationHotel; s_visualCategories[OsmTag("tourism", "motel")] = GeoDataPlacemark::AccomodationMotel; s_visualCategories[OsmTag("tourism", "alpine_hut")] = GeoDataPlacemark::TourismAlpineHut; s_visualCategories[OsmTag("tourism", "artwork")] = GeoDataPlacemark::TourismArtwork; s_visualCategories[OsmTag("tourism", "attraction")] = GeoDataPlacemark::TourismAttraction; s_visualCategories[OsmTag("tourism", "museum")] = GeoDataPlacemark::TourismMuseum; s_visualCategories[OsmTag("tourism", "theme_park")] = GeoDataPlacemark::TourismThemePark; s_visualCategories[OsmTag("tourism", "viewpoint")] = GeoDataPlacemark::TourismViewPoint; s_visualCategories[OsmTag("tourism", "wilderness_hut")] = GeoDataPlacemark::TourismWildernessHut; s_visualCategories[OsmTag("tourism", "zoo")] = GeoDataPlacemark::TourismZoo; s_visualCategories[OsmTag("barrier", "city_wall")] = GeoDataPlacemark::BarrierCityWall; s_visualCategories[OsmTag("barrier", "gate")] = GeoDataPlacemark::BarrierGate; s_visualCategories[OsmTag("barrier", "lift_gate")] = GeoDataPlacemark::BarrierLiftGate; s_visualCategories[OsmTag("barrier", "wall")] = GeoDataPlacemark::BarrierWall; s_visualCategories[OsmTag("highway", "traffic_signals")] = GeoDataPlacemark::HighwayTrafficSignals; s_visualCategories[OsmTag("highway", "cycleway")] = GeoDataPlacemark::HighwayCycleway; s_visualCategories[OsmTag("highway", "footway")] = GeoDataPlacemark::HighwayFootway; s_visualCategories[OsmTag("highway", "living_street")] = GeoDataPlacemark::HighwayLivingStreet; s_visualCategories[OsmTag("highway", "motorway")] = GeoDataPlacemark::HighwayMotorway; s_visualCategories[OsmTag("highway", "motorway_link")] = GeoDataPlacemark::HighwayMotorwayLink; s_visualCategories[OsmTag("highway", "path")] = GeoDataPlacemark::HighwayPath; s_visualCategories[OsmTag("highway", "pedestrian")] = GeoDataPlacemark::HighwayPedestrian; s_visualCategories[OsmTag("highway", "primary")] = GeoDataPlacemark::HighwayPrimary; s_visualCategories[OsmTag("highway", "primary_link")] = GeoDataPlacemark::HighwayPrimaryLink; s_visualCategories[OsmTag("highway", "raceway")] = GeoDataPlacemark::HighwayRaceway; s_visualCategories[OsmTag("highway", "residential")] = GeoDataPlacemark::HighwayResidential; s_visualCategories[OsmTag("highway", "road")] = GeoDataPlacemark::HighwayRoad; s_visualCategories[OsmTag("highway", "secondary")] = GeoDataPlacemark::HighwaySecondary; s_visualCategories[OsmTag("highway", "secondary_link")] = GeoDataPlacemark::HighwaySecondaryLink; s_visualCategories[OsmTag("highway", "service")] = GeoDataPlacemark::HighwayService; s_visualCategories[OsmTag("highway", "steps")] = GeoDataPlacemark::HighwaySteps; s_visualCategories[OsmTag("highway", "tertiary")] = GeoDataPlacemark::HighwayTertiary; s_visualCategories[OsmTag("highway", "tertiary_link")] = GeoDataPlacemark::HighwayTertiaryLink; s_visualCategories[OsmTag("highway", "track")] = GeoDataPlacemark::HighwayTrack; s_visualCategories[OsmTag("highway", "trunk")] = GeoDataPlacemark::HighwayTrunk; s_visualCategories[OsmTag("highway", "trunk_link")] = GeoDataPlacemark::HighwayTrunkLink; s_visualCategories[OsmTag("highway", "unclassified")] = GeoDataPlacemark::HighwayUnclassified; s_visualCategories[OsmTag("highway", "unknown")] = GeoDataPlacemark::HighwayUnknown; s_visualCategories[OsmTag("highway", "corridor")] = GeoDataPlacemark::HighwayCorridor; s_visualCategories[OsmTag("natural", "bay")] = GeoDataPlacemark::NaturalWater; s_visualCategories[OsmTag("natural", "coastline")] = GeoDataPlacemark::NaturalWater; s_visualCategories[OsmTag("natural", "reef")] = GeoDataPlacemark::NaturalReef; s_visualCategories[OsmTag("natural", "water")] = GeoDataPlacemark::NaturalWater; s_visualCategories[OsmTag("waterway", "canal")] = GeoDataPlacemark::WaterwayCanal; s_visualCategories[OsmTag("waterway", "ditch")] = GeoDataPlacemark::WaterwayDitch; s_visualCategories[OsmTag("waterway", "drain")] = GeoDataPlacemark::WaterwayDrain; s_visualCategories[OsmTag("waterway", "river")] = GeoDataPlacemark::WaterwayRiver; s_visualCategories[OsmTag("waterway", "riverbank")] = GeoDataPlacemark::NaturalWater; s_visualCategories[OsmTag("waterway", "weir")] = GeoDataPlacemark::WaterwayWeir; s_visualCategories[OsmTag("waterway", "stream")] = GeoDataPlacemark::WaterwayStream; s_visualCategories[OsmTag("natural", "beach")] = GeoDataPlacemark::NaturalBeach; s_visualCategories[OsmTag("natural", "cliff")] = GeoDataPlacemark::NaturalCliff; s_visualCategories[OsmTag("natural", "glacier")] = GeoDataPlacemark::NaturalGlacier; s_visualCategories[OsmTag("glacier:type", "shelf")] = GeoDataPlacemark::NaturalIceShelf; s_visualCategories[OsmTag("natural", "scrub")] = GeoDataPlacemark::NaturalScrub; s_visualCategories[OsmTag("natural", "wetland")] = GeoDataPlacemark::NaturalWetland; s_visualCategories[OsmTag("natural", "wood")] = GeoDataPlacemark::NaturalWood; s_visualCategories[OsmTag("military", "danger_area")] = GeoDataPlacemark::MilitaryDangerArea; s_visualCategories[OsmTag("landuse", "allotments")] = GeoDataPlacemark::LanduseAllotments; s_visualCategories[OsmTag("landuse", "basin")] = GeoDataPlacemark::LanduseBasin; s_visualCategories[OsmTag("landuse", "brownfield")] = GeoDataPlacemark::LanduseConstruction; s_visualCategories[OsmTag("landuse", "cemetery")] = GeoDataPlacemark::LanduseCemetery; s_visualCategories[OsmTag("landuse", "commercial")] = GeoDataPlacemark::LanduseCommercial; s_visualCategories[OsmTag("landuse", "construction")] = GeoDataPlacemark::LanduseConstruction; s_visualCategories[OsmTag("landuse", "farm")] = GeoDataPlacemark::LanduseFarmland; s_visualCategories[OsmTag("landuse", "farmland")] = GeoDataPlacemark::LanduseFarmland; s_visualCategories[OsmTag("landuse", "farmyard")] = GeoDataPlacemark::LanduseFarmland; s_visualCategories[OsmTag("landuse", "forest")] = GeoDataPlacemark::NaturalWood; s_visualCategories[OsmTag("landuse", "garages")] = GeoDataPlacemark::LanduseGarages; s_visualCategories[OsmTag("landuse", "grass")] = GeoDataPlacemark::LanduseGrass; s_visualCategories[OsmTag("landuse", "greenfield")] = GeoDataPlacemark::LanduseConstruction; s_visualCategories[OsmTag("landuse", "greenhouse_horticulture")] = GeoDataPlacemark::LanduseFarmland; s_visualCategories[OsmTag("landuse", "industrial")] = GeoDataPlacemark::LanduseIndustrial; s_visualCategories[OsmTag("landuse", "landfill")] = GeoDataPlacemark::LanduseLandfill; s_visualCategories[OsmTag("landuse", "meadow")] = GeoDataPlacemark::LanduseMeadow; s_visualCategories[OsmTag("landuse", "military")] = GeoDataPlacemark::LanduseMilitary; s_visualCategories[OsmTag("landuse", "orchard")] = GeoDataPlacemark::LanduseFarmland; s_visualCategories[OsmTag("landuse", "orchard")] = GeoDataPlacemark::LanduseOrchard; s_visualCategories[OsmTag("landuse", "quarry")] = GeoDataPlacemark::LanduseQuarry; s_visualCategories[OsmTag("landuse", "railway")] = GeoDataPlacemark::LanduseRailway; s_visualCategories[OsmTag("landuse", "recreation_ground")] = GeoDataPlacemark::LeisurePark; s_visualCategories[OsmTag("landuse", "reservoir")] = GeoDataPlacemark::LanduseReservoir; s_visualCategories[OsmTag("landuse", "residential")] = GeoDataPlacemark::LanduseResidential; s_visualCategories[OsmTag("landuse", "retail")] = GeoDataPlacemark::LanduseRetail; s_visualCategories[OsmTag("landuse", "village_green")] = GeoDataPlacemark::LanduseGrass; s_visualCategories[OsmTag("landuse", "vineyard")] = GeoDataPlacemark::LanduseVineyard; s_visualCategories[OsmTag("leisure", "common")] = GeoDataPlacemark::LanduseGrass; s_visualCategories[OsmTag("leisure", "garden")] = GeoDataPlacemark::LanduseGrass; s_visualCategories[OsmTag("leisure", "golf_course")] = GeoDataPlacemark::LeisureGolfCourse; s_visualCategories[OsmTag("leisure", "marina")] = GeoDataPlacemark::LeisureMarina; s_visualCategories[OsmTag("leisure", "miniature_golf")] = GeoDataPlacemark::LeisureMinigolfCourse; s_visualCategories[OsmTag("leisure", "park")] = GeoDataPlacemark::LeisurePark; s_visualCategories[OsmTag("leisure", "pitch")] = GeoDataPlacemark::LeisurePitch; s_visualCategories[OsmTag("leisure", "playground")] = GeoDataPlacemark::LeisurePlayground; s_visualCategories[OsmTag("leisure", "sports_centre")] = GeoDataPlacemark::LeisureSportsCentre; s_visualCategories[OsmTag("leisure", "stadium")] = GeoDataPlacemark::LeisureStadium; s_visualCategories[OsmTag("leisure", "swimming_pool")] = GeoDataPlacemark::LeisureSwimmingPool; s_visualCategories[OsmTag("leisure", "track")] = GeoDataPlacemark::LeisureTrack; s_visualCategories[OsmTag("leisure", "water_park")] = GeoDataPlacemark::LeisureWaterPark; s_visualCategories[OsmTag("railway", "abandoned")] = GeoDataPlacemark::RailwayAbandoned; s_visualCategories[OsmTag("railway", "construction")] = GeoDataPlacemark::RailwayConstruction; s_visualCategories[OsmTag("railway", "disused")] = GeoDataPlacemark::RailwayAbandoned; s_visualCategories[OsmTag("railway", "funicular")] = GeoDataPlacemark::RailwayFunicular; s_visualCategories[OsmTag("railway", "halt")] = GeoDataPlacemark::TransportTrainStation; s_visualCategories[OsmTag("railway", "light_rail")] = GeoDataPlacemark::RailwayLightRail; s_visualCategories[OsmTag("railway", "miniature")] = GeoDataPlacemark::RailwayMiniature; s_visualCategories[OsmTag("railway", "monorail")] = GeoDataPlacemark::RailwayMonorail; s_visualCategories[OsmTag("railway", "narrow_gauge")] = GeoDataPlacemark::RailwayNarrowGauge; s_visualCategories[OsmTag("railway", "platform")] = GeoDataPlacemark::TransportPlatform; s_visualCategories[OsmTag("railway", "preserved")] = GeoDataPlacemark::RailwayPreserved; s_visualCategories[OsmTag("railway", "rail")] = GeoDataPlacemark::RailwayRail; s_visualCategories[OsmTag("railway", "razed")] = GeoDataPlacemark::RailwayAbandoned; s_visualCategories[OsmTag("railway", "station")] = GeoDataPlacemark::TransportTrainStation; s_visualCategories[OsmTag("public_transport", "station")] = GeoDataPlacemark::TransportTrainStation; s_visualCategories[OsmTag("railway", "subway")] = GeoDataPlacemark::RailwaySubway; s_visualCategories[OsmTag("railway", "tram")] = GeoDataPlacemark::RailwayTram; s_visualCategories[OsmTag("power", "tower")] = GeoDataPlacemark::PowerTower; s_visualCategories[OsmTag("aeroway", "aerodrome")] = GeoDataPlacemark::TransportAerodrome; s_visualCategories[OsmTag("aeroway", "apron")] = GeoDataPlacemark::TransportAirportApron; s_visualCategories[OsmTag("aeroway", "gate")] = GeoDataPlacemark::TransportAirportGate; s_visualCategories[OsmTag("aeroway", "helipad")] = GeoDataPlacemark::TransportHelipad; s_visualCategories[OsmTag("aeroway", "runway")] = GeoDataPlacemark::TransportAirportRunway; s_visualCategories[OsmTag("aeroway", "taxiway")] = GeoDataPlacemark::TransportAirportTaxiway; s_visualCategories[OsmTag("aeroway", "terminal")] = GeoDataPlacemark::TransportAirportTerminal; s_visualCategories[OsmTag("piste:type", "downhill")] = GeoDataPlacemark::PisteDownhill; s_visualCategories[OsmTag("piste:type", "nordic")] = GeoDataPlacemark::PisteNordic; s_visualCategories[OsmTag("piste:type", "skitour")] = GeoDataPlacemark::PisteSkitour; s_visualCategories[OsmTag("piste:type", "sled")] = GeoDataPlacemark::PisteSled; s_visualCategories[OsmTag("piste:type", "hike")] = GeoDataPlacemark::PisteHike; s_visualCategories[OsmTag("piste:type", "sleigh")] = GeoDataPlacemark::PisteSleigh; s_visualCategories[OsmTag("piste:type", "ice_skate")] = GeoDataPlacemark::PisteIceSkate; s_visualCategories[OsmTag("piste:type", "snow_park")] = GeoDataPlacemark::PisteSnowPark; s_visualCategories[OsmTag("piste:type", "playground")] = GeoDataPlacemark::PistePlayground; s_visualCategories[OsmTag("piste:type", "ski_jump")] = GeoDataPlacemark::PisteSkiJump; s_visualCategories[OsmTag("amenity", "bicycle_parking")] = GeoDataPlacemark::TransportBicycleParking; s_visualCategories[OsmTag("amenity", "bicycle_rental")] = GeoDataPlacemark::TransportRentalBicycle; s_visualCategories[OsmTag("rental", "bicycle")] = GeoDataPlacemark::TransportRentalBicycle; s_visualCategories[OsmTag("amenity", "car_rental")] = GeoDataPlacemark::TransportRentalCar; s_visualCategories[OsmTag("rental", "car")] = GeoDataPlacemark::TransportRentalCar; s_visualCategories[OsmTag("amenity", "ski_rental")] = GeoDataPlacemark::TransportRentalSki; s_visualCategories[OsmTag("rental", "ski")] = GeoDataPlacemark::TransportRentalSki; s_visualCategories[OsmTag("amenity", "motorcycle_parking")] = GeoDataPlacemark::TransportMotorcycleParking; s_visualCategories[OsmTag("amenity", "taxi")] = GeoDataPlacemark::TransportTaxiRank; s_visualCategories[OsmTag("highway", "bus_stop")] = GeoDataPlacemark::TransportBusStop; s_visualCategories[OsmTag("highway", "speed_camera")] = GeoDataPlacemark::TransportSpeedCamera; s_visualCategories[OsmTag("public_transport", "platform")] = GeoDataPlacemark::TransportPlatform; s_visualCategories[OsmTag("railway", "subway_entrance")] = GeoDataPlacemark::TransportSubwayEntrance; s_visualCategories[OsmTag("railway", "tram_stop")] = GeoDataPlacemark::TransportTramStop; s_visualCategories[OsmTag("place", "city")] = GeoDataPlacemark::PlaceCity; s_visualCategories[OsmTag("place", "hamlet")] = GeoDataPlacemark::PlaceHamlet; s_visualCategories[OsmTag("place", "locality")] = GeoDataPlacemark::PlaceLocality; s_visualCategories[OsmTag("place", "suburb")] = GeoDataPlacemark::PlaceSuburb; s_visualCategories[OsmTag("place", "town")] = GeoDataPlacemark::PlaceTown; s_visualCategories[OsmTag("place", "village")] = GeoDataPlacemark::PlaceVillage; s_visualCategories[OsmTag("aerialway", "station")] = GeoDataPlacemark::AerialwayStation; s_visualCategories[OsmTag("aerialway", "pylon")] = GeoDataPlacemark::AerialwayPylon; s_visualCategories[OsmTag("aerialway", "cable_car")] = GeoDataPlacemark::AerialwayCableCar; s_visualCategories[OsmTag("aerialway", "gondola")] = GeoDataPlacemark::AerialwayGondola; s_visualCategories[OsmTag("aerialway", "chair_lift")] = GeoDataPlacemark::AerialwayChairLift; s_visualCategories[OsmTag("aerialway", "mixed_lift")] = GeoDataPlacemark::AerialwayMixedLift; s_visualCategories[OsmTag("aerialway", "drag_lift")] = GeoDataPlacemark::AerialwayDragLift; s_visualCategories[OsmTag("aerialway", "t-bar")] = GeoDataPlacemark::AerialwayTBar; s_visualCategories[OsmTag("aerialway", "j-bar")] = GeoDataPlacemark::AerialwayJBar; s_visualCategories[OsmTag("aerialway", "platter")] = GeoDataPlacemark::AerialwayPlatter; s_visualCategories[OsmTag("aerialway", "rope_tow")] = GeoDataPlacemark::AerialwayRopeTow; s_visualCategories[OsmTag("aerialway", "magic_carpet")] = GeoDataPlacemark::AerialwayMagicCarpet; s_visualCategories[OsmTag("aerialway", "zip_line")] = GeoDataPlacemark::AerialwayZipLine; s_visualCategories[OsmTag("aerialway", "goods")] = GeoDataPlacemark::AerialwayGoods; //Custom Marble OSM Tags s_visualCategories[OsmTag("marble_land", "landmass")] = GeoDataPlacemark::Landmass; s_visualCategories[OsmTag("settlement", "yes")] = GeoDataPlacemark::UrbanArea; s_visualCategories[OsmTag("marble_line", "date")] = GeoDataPlacemark::InternationalDateLine; s_visualCategories[OsmTag("marble:feature", "bathymetry")] = GeoDataPlacemark::Bathymetry; // Default for buildings for (const auto &tag: buildingTags()) { s_visualCategories[tag] = GeoDataPlacemark::Building; } } void StyleBuilder::Private::initializeMinimumZoomLevels() { if (s_defaultMinZoomLevelsInitialized) { return; } s_defaultMinZoomLevelsInitialized = true; for (int i = 0; i < GeoDataPlacemark::LastIndex; i++) { s_defaultMinZoomLevels[i] = -1; } s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel10] = 8; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel11] = 8; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel1] = 0; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel2] = 1; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel3] = 1; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel4] = 2; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel5] = 4; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel6] = 5; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel7] = 5; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel8] = 7; s_defaultMinZoomLevels[GeoDataPlacemark::AdminLevel9] = 7; s_defaultMinZoomLevels[GeoDataPlacemark::HistoricArchaeologicalSite] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityBench] = 19; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityFountain] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityGraveyard] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityTelephone] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityKindergarten] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityLibrary] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityWasteBasket] = 19; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityToilets] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityTownHall] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::LeisureWaterPark] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityDrinkingWater] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityEmbassy] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityEmergencyPhone] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityMountainRescue] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityCommunityCentre] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityFountain] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityNightClub] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityCourtHouse] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityFireStation] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityHuntingStand] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityPolice] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityPostBox] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityPostOffice] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityPrison] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityRecycling] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityShelter] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityChargingStation] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityCarWash] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::AmenitySocialFacility] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::BarrierCityWall] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::BarrierGate] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::BarrierLiftGate] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::BarrierWall] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::Bathymetry] = 1; s_defaultMinZoomLevels[GeoDataPlacemark::BoundaryMaritime] = 1; s_defaultMinZoomLevels[GeoDataPlacemark::Building] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::Default] = 1; s_defaultMinZoomLevels[GeoDataPlacemark::EducationCollege] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::EducationSchool] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::EducationUniversity] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::FoodBar] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::FoodBiergarten] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::FoodCafe] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::FoodFastFood] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::FoodPub] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::FoodRestaurant] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::HealthHospital] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::HealthPharmacy] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::HealthDentist] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::HealthDoctors] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::HealthVeterinary] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::HistoricMemorial] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayCycleway] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayFootway] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayLivingStreet] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayMotorwayLink] = 10; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayMotorway] = 6; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayPath] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayPedestrian] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayPrimaryLink] = 10; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayPrimary] = 8; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayRaceway] = 12; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayResidential] = 14; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayRoad] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::HighwaySecondaryLink] = 10; s_defaultMinZoomLevels[GeoDataPlacemark::HighwaySecondary] = 9; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayService] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::HighwaySteps] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayTertiaryLink] = 10; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayTertiary] = 10; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayTrack] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayTrunkLink] = 10; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayTrunk] = 7; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayUnknown] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayUnclassified] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayTrafficSignals] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::HighwayCorridor] = 18; s_defaultMinZoomLevels[GeoDataPlacemark::AccomodationCamping] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AccomodationHostel] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AccomodationHotel] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AccomodationMotel] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AccomodationYouthHostel] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AccomodationGuestHouse] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::InternationalDateLine] = 1; s_defaultMinZoomLevels[GeoDataPlacemark::Landmass] = 0; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseAllotments] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseBasin] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseCemetery] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseCommercial] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseConstruction] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseFarmland] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseFarmyard] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseGarages] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseGrass] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseIndustrial] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseLandfill] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseMeadow] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseMilitary] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseOrchard] = 14; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseQuarry] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseRailway] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseReservoir] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseResidential] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseRetail] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::LanduseVineyard] = 14; s_defaultMinZoomLevels[GeoDataPlacemark::LeisureGolfCourse] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::LeisureMarina] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::LeisurePark] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::LeisurePlayground] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::LeisurePitch] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::LeisureStadium] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::LeisureSwimmingPool] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::LeisureSportsCentre] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::LeisureTrack] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::LeisureMinigolfCourse] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::ManmadeBridge] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::ManmadeLighthouse] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::ManmadePier] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::ManmadeWaterTower] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::ManmadeWindMill] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::MilitaryDangerArea] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::MoneyAtm] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::MoneyBank] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalBeach] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalCliff] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalGlacier] = 3; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalHeath] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalIceShelf] = 3; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalVolcano] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalPeak] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalReef] = 3; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalScrub] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalTree] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalCave] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalWater] = 3; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalWetland] = 10; s_defaultMinZoomLevels[GeoDataPlacemark::NaturalWood] = 8; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceCityNationalCapital] = 9; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceCityCapital] = 9; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceCity] = 9; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceHamlet] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceLocality] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceSuburb] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceTownNationalCapital] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceTownCapital] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceTown] = 11; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceVillageNationalCapital] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceVillageCapital] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::PlaceVillage] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::PowerTower] = 18; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayAbandoned] = 10; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayConstruction] = 10; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayFunicular] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayLightRail] = 12; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayMiniature] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayMonorail] = 12; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayNarrowGauge] = 6; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayPreserved] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayRail] = 6; s_defaultMinZoomLevels[GeoDataPlacemark::RailwaySubway] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::RailwayTram] = 14; s_defaultMinZoomLevels[GeoDataPlacemark::Satellite] = 0; for (int shop = GeoDataPlacemark::ShopBeverages; shop <= GeoDataPlacemark::Shop; ++shop) { s_defaultMinZoomLevels[shop] = 17; } s_defaultMinZoomLevels[GeoDataPlacemark::ShopSupermarket] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::ShopDepartmentStore] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::ShopDoitYourself] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TourismAlpineHut] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::TourismWildernessHut] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::TourismAttraction] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::TourismArtwork] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::HistoricCastle] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityCinema] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TourismMuseum] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::HistoricRuins] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AmenityTheatre] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TourismThemePark] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::TourismViewPoint] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::TourismZoo] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::HistoricMonument] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TourismInformation] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::TransportAerodrome] = 9; s_defaultMinZoomLevels[GeoDataPlacemark::TransportAirportApron] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::TransportAirportRunway] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::TransportAirportTaxiway] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::TransportBusStation] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::TransportCarShare] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TransportFuel] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TransportHelipad] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TransportAirportTerminal] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::TransportAirportGate] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::TransportPlatform] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TransportSpeedCamera] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TransportRentalCar] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TransportRentalBicycle] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::TransportRentalSki] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::TransportTaxiRank] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TransportParking] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TransportBusStop] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::TransportTrainStation] = 13; s_defaultMinZoomLevels[GeoDataPlacemark::TransportTramStop] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::TransportParkingSpace] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::TransportBicycleParking] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::TransportMotorcycleParking] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::TransportSubwayEntrance] = 17; for (int religion = GeoDataPlacemark::ReligionPlaceOfWorship; religion <= GeoDataPlacemark::ReligionSikh; ++religion) { s_defaultMinZoomLevels[religion] = 17; } s_defaultMinZoomLevels[GeoDataPlacemark::UrbanArea] = 3; s_defaultMinZoomLevels[GeoDataPlacemark::WaterwayCanal] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::WaterwayDitch] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::WaterwayDrain] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::WaterwayStream] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::WaterwayRiver] = 3; s_defaultMinZoomLevels[GeoDataPlacemark::WaterwayWeir] = 17; s_defaultMinZoomLevels[GeoDataPlacemark::CrossingIsland] = 18; s_defaultMinZoomLevels[GeoDataPlacemark::CrossingRailway] = 18; s_defaultMinZoomLevels[GeoDataPlacemark::CrossingSignals] = 18; s_defaultMinZoomLevels[GeoDataPlacemark::CrossingZebra] = 18; s_defaultMinZoomLevels[GeoDataPlacemark::PisteDownhill] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PisteNordic] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PisteSkitour] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PisteSled] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PisteHike] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PisteSleigh] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PisteIceSkate] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PisteSnowPark] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PistePlayground] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::PisteSkiJump] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayStation] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayPylon] = 16; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayCableCar] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayGondola] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayChairLift] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayMixedLift] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayDragLift] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayTBar] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayJBar] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayPlatter] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayRopeTow] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayMagicCarpet] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayZipLine] = 15; s_defaultMinZoomLevels[GeoDataPlacemark::AerialwayGoods] = 15; for (int i = GeoDataPlacemark::PlaceCity; i < GeoDataPlacemark::LastIndex; i++) { if (s_defaultMinZoomLevels[i] < 0) { qDebug() << "Missing default min zoom level for GeoDataPlacemark::GeoDataVisualCategory " << i; Q_ASSERT(false && "StyleBuilder::Private::initializeMinimumZoomLevels is incomplete"); s_defaultMinZoomLevels[i] = 15; } } } StyleBuilder::StyleBuilder() : d(new Private) { // nothing to do } StyleBuilder::~StyleBuilder() { delete d; } QFont StyleBuilder::defaultFont() const { return d->m_defaultFont; } void StyleBuilder::setDefaultFont(const QFont& font) { d->m_defaultFont = font; reset(); } QColor StyleBuilder::defaultLabelColor() const { return d->m_defaultLabelColor; } void StyleBuilder::setDefaultLabelColor(const QColor& color) { d->m_defaultLabelColor = color; reset(); } GeoDataStyle::ConstPtr StyleBuilder::createStyle(const StyleParameters ¶meters) const { const GeoDataPlacemark *const placemark = parameters.placemark; if (!placemark) { Q_ASSERT(false && "Must not pass a null placemark to StyleBuilder::createStyle"); return GeoDataStyle::Ptr(); } if (placemark->customStyle()) { return placemark->customStyle(); } if (parameters.relation) { auto style = d->createRelationStyle(parameters); if (style) { return style; } } return d->createPlacemarkStyle(parameters); } GeoDataStyle::ConstPtr StyleBuilder::Private::presetStyle(GeoDataPlacemark::GeoDataVisualCategory visualCategory) const { if (!m_defaultStyleInitialized) { const_cast(this)->initializeDefaultStyles(); // const cast due to lazy initialization } if (visualCategory != GeoDataPlacemark::None && m_defaultStyle[visualCategory]) { return m_defaultStyle[visualCategory]; } else { return m_defaultStyle[GeoDataPlacemark::Default]; } } QStringList StyleBuilder::renderOrder() const { static QStringList paintLayerOrder; if (paintLayerOrder.isEmpty()) { paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::Landmass); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::UrbanArea); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseResidential); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseAllotments); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseBasin); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseCemetery); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseCommercial); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseConstruction); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseFarmland); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseFarmyard); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseGarages); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseIndustrial); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseLandfill); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseMeadow); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseMilitary); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseQuarry); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseRailway); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseReservoir); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseRetail); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseOrchard); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseVineyard); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::Bathymetry); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisureGolfCourse); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisureMinigolfCourse); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalBeach); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalWetland); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalGlacier); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalIceShelf); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalVolcano); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalCliff); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalPeak); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::MilitaryDangerArea); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisurePark); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisurePitch); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisureSportsCentre); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisureStadium); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalWood); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LanduseGrass); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::HighwayPedestrian); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisurePlayground); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalScrub); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisureTrack); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::TransportParking); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::TransportParkingSpace); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::ManmadeBridge); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::BarrierCityWall); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::AmenityGraveyard); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::AmenityKindergarten); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::EducationCollege); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::EducationSchool); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::EducationUniversity); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::HealthHospital); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisureSwimmingPool); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::Landmass); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::NaturalWater); for (int i = GeoDataPlacemark::WaterwayCanal; i <= GeoDataPlacemark::WaterwayStream; ++i) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "outline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "inline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "label"); } paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::NaturalReef, "outline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::NaturalReef, "inline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::NaturalReef, "label"); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::LeisureMarina); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::ManmadePier); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::ManmadePier, "outline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::ManmadePier, "inline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::ManmadePier, "label"); paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::TransportAirportApron); for (int i = GeoDataPlacemark::HighwaySteps; i <= GeoDataPlacemark::HighwayMotorway; i++) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "outline"); } for (int i = GeoDataPlacemark::HighwaySteps; i <= GeoDataPlacemark::HighwayMotorway; i++) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "inline"); } for (int i = GeoDataPlacemark::RailwayRail; i <= GeoDataPlacemark::RailwayFunicular; i++) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "outline"); } for (int i = GeoDataPlacemark::RailwayRail; i <= GeoDataPlacemark::RailwayFunicular; i++) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "inline"); } // Highway labels shall appear on top of railways, hence here and not already above for (int i = GeoDataPlacemark::HighwaySteps; i <= GeoDataPlacemark::HighwayMotorway; i++) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "label"); } for (int i = GeoDataPlacemark::RailwayRail; i <= GeoDataPlacemark::RailwayFunicular; i++) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "label"); } paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::TransportPlatform); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::TransportPlatform, "outline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::TransportPlatform, "inline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::TransportPlatform, "label"); for (int i = GeoDataPlacemark::PisteDownhill; i <= GeoDataPlacemark::PisteSkiJump; ++i) { paintLayerOrder << Private::createPaintLayerItem("Polygon", GeoDataPlacemark::GeoDataVisualCategory(i)); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "outline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "inline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "label"); } for (int i = GeoDataPlacemark::AerialwayCableCar; i <= GeoDataPlacemark::AerialwayGoods; ++i) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "outline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "inline"); paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "label"); } for (int i = GeoDataPlacemark::AdminLevel1; i <= GeoDataPlacemark::AdminLevel11; i++) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "outline"); } for (int i = GeoDataPlacemark::AdminLevel1; i <= GeoDataPlacemark::AdminLevel11; i++) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "inline"); } for (int i = GeoDataPlacemark::AdminLevel1; i <= GeoDataPlacemark::AdminLevel11; i++) { paintLayerOrder << Private::createPaintLayerItem("LineString", GeoDataPlacemark::GeoDataVisualCategory(i), "label"); } paintLayerOrder << QStringLiteral("Polygon/Building/frame"); paintLayerOrder << QStringLiteral("Polygon/Building/roof"); paintLayerOrder << QStringLiteral("Photo"); Q_ASSERT(QSet::fromList(paintLayerOrder).size() == paintLayerOrder.size()); } return paintLayerOrder; } void StyleBuilder::reset() { d->m_defaultStyleInitialized = false; } int StyleBuilder::minimumZoomLevel(const GeoDataPlacemark &placemark) const { Q_ASSERT(Private::s_defaultMinZoomLevelsInitialized); return Private::s_defaultMinZoomLevels[placemark.visualCategory()]; } int StyleBuilder::minimumZoomLevel(const GeoDataPlacemark::GeoDataVisualCategory &visualCategory) { Private::initializeMinimumZoomLevels(); return Private::s_defaultMinZoomLevels[visualCategory]; } qint64 StyleBuilder::popularity(const GeoDataPlacemark *placemark) { qint64 const defaultValue = 100; int const offset = 10; if (StyleBuilder::Private::s_popularities.isEmpty()) { QVector popularities; popularities << GeoDataPlacemark::PlaceCityNationalCapital; popularities << GeoDataPlacemark::PlaceTownNationalCapital; popularities << GeoDataPlacemark::PlaceCityCapital; popularities << GeoDataPlacemark::PlaceTownCapital; popularities << GeoDataPlacemark::PlaceCity; popularities << GeoDataPlacemark::PlaceTown; popularities << GeoDataPlacemark::PlaceSuburb; popularities << GeoDataPlacemark::PlaceVillageNationalCapital; popularities << GeoDataPlacemark::PlaceVillageCapital; popularities << GeoDataPlacemark::PlaceVillage; popularities << GeoDataPlacemark::PlaceHamlet; popularities << GeoDataPlacemark::PlaceLocality; popularities << GeoDataPlacemark::AmenityEmergencyPhone; popularities << GeoDataPlacemark::AmenityMountainRescue; popularities << GeoDataPlacemark::HealthHospital; popularities << GeoDataPlacemark::AmenityToilets; popularities << GeoDataPlacemark::MoneyAtm; popularities << GeoDataPlacemark::TransportSpeedCamera; popularities << GeoDataPlacemark::NaturalPeak; popularities << GeoDataPlacemark::NaturalVolcano; popularities << GeoDataPlacemark::AccomodationHotel; popularities << GeoDataPlacemark::AccomodationMotel; popularities << GeoDataPlacemark::AccomodationGuestHouse; popularities << GeoDataPlacemark::AccomodationYouthHostel; popularities << GeoDataPlacemark::AccomodationHostel; popularities << GeoDataPlacemark::AccomodationCamping; popularities << GeoDataPlacemark::HealthDentist; popularities << GeoDataPlacemark::HealthDoctors; popularities << GeoDataPlacemark::HealthPharmacy; popularities << GeoDataPlacemark::HealthVeterinary; popularities << GeoDataPlacemark::AmenityLibrary; popularities << GeoDataPlacemark::EducationCollege; popularities << GeoDataPlacemark::EducationSchool; popularities << GeoDataPlacemark::EducationUniversity; popularities << GeoDataPlacemark::FoodBar; popularities << GeoDataPlacemark::FoodBiergarten; popularities << GeoDataPlacemark::FoodCafe; popularities << GeoDataPlacemark::FoodFastFood; popularities << GeoDataPlacemark::FoodPub; popularities << GeoDataPlacemark::FoodRestaurant; popularities << GeoDataPlacemark::MoneyBank; popularities << GeoDataPlacemark::HistoricArchaeologicalSite; popularities << GeoDataPlacemark::AmenityCarWash; popularities << GeoDataPlacemark::AmenityEmbassy; popularities << GeoDataPlacemark::LeisureWaterPark; popularities << GeoDataPlacemark::AmenityCommunityCentre; popularities << GeoDataPlacemark::AmenityFountain; popularities << GeoDataPlacemark::AmenityNightClub; popularities << GeoDataPlacemark::AmenityCourtHouse; popularities << GeoDataPlacemark::AmenityFireStation; popularities << GeoDataPlacemark::AmenityShelter; popularities << GeoDataPlacemark::AmenityHuntingStand; popularities << GeoDataPlacemark::AmenityPolice; popularities << GeoDataPlacemark::AmenityPostBox; popularities << GeoDataPlacemark::AmenityPostOffice; popularities << GeoDataPlacemark::AmenityPrison; popularities << GeoDataPlacemark::AmenityRecycling; popularities << GeoDataPlacemark::AmenitySocialFacility; popularities << GeoDataPlacemark::AmenityTelephone; popularities << GeoDataPlacemark::AmenityTownHall; popularities << GeoDataPlacemark::AmenityDrinkingWater; popularities << GeoDataPlacemark::AmenityGraveyard; popularities << GeoDataPlacemark::ManmadeBridge; popularities << GeoDataPlacemark::ManmadeLighthouse; popularities << GeoDataPlacemark::ManmadePier; popularities << GeoDataPlacemark::ManmadeWaterTower; popularities << GeoDataPlacemark::ManmadeWindMill; popularities << GeoDataPlacemark::TourismAttraction; popularities << GeoDataPlacemark::TourismArtwork; popularities << GeoDataPlacemark::HistoricCastle; popularities << GeoDataPlacemark::AmenityCinema; popularities << GeoDataPlacemark::TourismInformation; popularities << GeoDataPlacemark::HistoricMonument; popularities << GeoDataPlacemark::TourismMuseum; popularities << GeoDataPlacemark::HistoricRuins; popularities << GeoDataPlacemark::AmenityTheatre; popularities << GeoDataPlacemark::TourismThemePark; popularities << GeoDataPlacemark::TourismViewPoint; popularities << GeoDataPlacemark::TourismZoo; popularities << GeoDataPlacemark::TourismAlpineHut; popularities << GeoDataPlacemark::TourismWildernessHut; popularities << GeoDataPlacemark::HistoricMemorial; popularities << GeoDataPlacemark::TransportAerodrome; popularities << GeoDataPlacemark::TransportHelipad; popularities << GeoDataPlacemark::TransportAirportTerminal; popularities << GeoDataPlacemark::TransportBusStation; popularities << GeoDataPlacemark::TransportBusStop; popularities << GeoDataPlacemark::TransportCarShare; popularities << GeoDataPlacemark::TransportFuel; popularities << GeoDataPlacemark::TransportParking; popularities << GeoDataPlacemark::TransportParkingSpace; popularities << GeoDataPlacemark::TransportPlatform; popularities << GeoDataPlacemark::TransportRentalBicycle; popularities << GeoDataPlacemark::TransportRentalCar; popularities << GeoDataPlacemark::TransportRentalSki; popularities << GeoDataPlacemark::TransportTaxiRank; popularities << GeoDataPlacemark::TransportTrainStation; popularities << GeoDataPlacemark::TransportTramStop; popularities << GeoDataPlacemark::TransportBicycleParking; popularities << GeoDataPlacemark::TransportMotorcycleParking; popularities << GeoDataPlacemark::TransportSubwayEntrance; popularities << GeoDataPlacemark::AerialwayStation; popularities << GeoDataPlacemark::ShopBeverages; popularities << GeoDataPlacemark::ShopHifi; popularities << GeoDataPlacemark::ShopSupermarket; popularities << GeoDataPlacemark::ShopAlcohol; popularities << GeoDataPlacemark::ShopBakery; popularities << GeoDataPlacemark::ShopButcher; popularities << GeoDataPlacemark::ShopConfectionery; popularities << GeoDataPlacemark::ShopConvenience; popularities << GeoDataPlacemark::ShopGreengrocer; popularities << GeoDataPlacemark::ShopSeafood; popularities << GeoDataPlacemark::ShopDepartmentStore; popularities << GeoDataPlacemark::ShopKiosk; popularities << GeoDataPlacemark::ShopBag; popularities << GeoDataPlacemark::ShopClothes; popularities << GeoDataPlacemark::ShopFashion; popularities << GeoDataPlacemark::ShopJewelry; popularities << GeoDataPlacemark::ShopShoes; popularities << GeoDataPlacemark::ShopVarietyStore; popularities << GeoDataPlacemark::ShopBeauty; popularities << GeoDataPlacemark::ShopChemist; popularities << GeoDataPlacemark::ShopCosmetics; popularities << GeoDataPlacemark::ShopHairdresser; popularities << GeoDataPlacemark::ShopOptician; popularities << GeoDataPlacemark::ShopPerfumery; popularities << GeoDataPlacemark::ShopDoitYourself; popularities << GeoDataPlacemark::ShopFlorist; popularities << GeoDataPlacemark::ShopHardware; popularities << GeoDataPlacemark::ShopFurniture; popularities << GeoDataPlacemark::ShopElectronics; popularities << GeoDataPlacemark::ShopMobilePhone; popularities << GeoDataPlacemark::ShopBicycle; popularities << GeoDataPlacemark::ShopCar; popularities << GeoDataPlacemark::ShopCarRepair; popularities << GeoDataPlacemark::ShopCarParts; popularities << GeoDataPlacemark::ShopMotorcycle; popularities << GeoDataPlacemark::ShopOutdoor; popularities << GeoDataPlacemark::ShopSports; popularities << GeoDataPlacemark::ShopCopy; popularities << GeoDataPlacemark::ShopArt; popularities << GeoDataPlacemark::ShopMusicalInstrument; popularities << GeoDataPlacemark::ShopPhoto; popularities << GeoDataPlacemark::ShopBook; popularities << GeoDataPlacemark::ShopGift; popularities << GeoDataPlacemark::ShopStationery; popularities << GeoDataPlacemark::ShopLaundry; popularities << GeoDataPlacemark::ShopPet; popularities << GeoDataPlacemark::ShopToys; popularities << GeoDataPlacemark::ShopTravelAgency; popularities << GeoDataPlacemark::ShopDeli; popularities << GeoDataPlacemark::ShopTobacco; popularities << GeoDataPlacemark::ShopTea; popularities << GeoDataPlacemark::Shop; popularities << GeoDataPlacemark::LeisureGolfCourse; popularities << GeoDataPlacemark::LeisureMinigolfCourse; popularities << GeoDataPlacemark::LeisurePark; popularities << GeoDataPlacemark::LeisurePlayground; popularities << GeoDataPlacemark::LeisurePitch; popularities << GeoDataPlacemark::LeisureSportsCentre; popularities << GeoDataPlacemark::LeisureStadium; popularities << GeoDataPlacemark::LeisureTrack; popularities << GeoDataPlacemark::LeisureSwimmingPool; popularities << GeoDataPlacemark::CrossingIsland; popularities << GeoDataPlacemark::CrossingRailway; popularities << GeoDataPlacemark::CrossingSignals; popularities << GeoDataPlacemark::CrossingZebra; popularities << GeoDataPlacemark::HighwayTrafficSignals; popularities << GeoDataPlacemark::BarrierGate; popularities << GeoDataPlacemark::BarrierLiftGate; popularities << GeoDataPlacemark::AmenityBench; popularities << GeoDataPlacemark::NaturalTree; popularities << GeoDataPlacemark::NaturalCave; popularities << GeoDataPlacemark::AmenityWasteBasket; popularities << GeoDataPlacemark::AerialwayPylon; popularities << GeoDataPlacemark::PowerTower; int value = defaultValue + offset * popularities.size(); for (auto popularity : popularities) { StyleBuilder::Private::s_popularities[popularity] = value; value -= offset; } } bool const isPrivate = placemark->osmData().containsTag(QStringLiteral("access"), QStringLiteral("private")); int const base = defaultValue + (isPrivate ? 0 : offset * StyleBuilder::Private::s_popularities.size()); return base + StyleBuilder::Private::s_popularities.value(placemark->visualCategory(), defaultValue); } int StyleBuilder::maximumZoomLevel() const { return d->m_maximumZoomLevel; } QString StyleBuilder::visualCategoryName(GeoDataPlacemark::GeoDataVisualCategory category) { static QHash visualCategoryNames; if (visualCategoryNames.isEmpty()) { visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::None] = "None"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Default] = "Default"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Unknown] = "Unknown"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::SmallCity] = "SmallCity"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::SmallCountyCapital] = "SmallCountyCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::SmallStateCapital] = "SmallStateCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::SmallNationCapital] = "SmallNationCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::MediumCity] = "MediumCity"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::MediumCountyCapital] = "MediumCountyCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::MediumStateCapital] = "MediumStateCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::MediumNationCapital] = "MediumNationCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::BigCity] = "BigCity"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::BigCountyCapital] = "BigCountyCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::BigStateCapital] = "BigStateCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::BigNationCapital] = "BigNationCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::LargeCity] = "LargeCity"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::LargeCountyCapital] = "LargeCountyCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::LargeStateCapital] = "LargeStateCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::LargeNationCapital] = "LargeNationCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Nation] = "Nation"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceCity] = "PlaceCity"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceCityCapital] = "PlaceCityCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceCityNationalCapital] = "PlaceCityNationalCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceSuburb] = "PlaceSuburb"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceHamlet] = "PlaceHamlet"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceLocality] = "PlaceLocality"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceTown] = "PlaceTown"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceTownCapital] = "PlaceTownCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceTownNationalCapital] = "PlaceTownNationalCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceVillage] = "PlaceVillage"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceVillageCapital] = "PlaceVillageCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::PlaceVillageNationalCapital] = "PlaceVillageNationalCapital"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Mountain] = "Mountain"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Volcano] = "Volcano"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Mons] = "Mons"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Valley] = "Valley"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Continent] = "Continent"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Ocean] = "Ocean"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::OtherTerrain] = "OtherTerrain"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Crater] = "Crater"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Mare] = "Mare"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::GeographicPole] = "GeographicPole"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::MagneticPole] = "MagneticPole"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::ShipWreck] = "ShipWreck"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::AirPort] = "AirPort"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::Observatory] = "Observatory"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::MilitaryDangerArea] = "MilitaryDangerArea"; visualCategoryNames[GeoDataPlacemark::GeoDataPlacemark::OsmSite] = "OsmSite"; visualCategoryNames[GeoDataPlacemark::Coordinate] = "Coordinate"; visualCategoryNames[GeoDataPlacemark::MannedLandingSite] = "MannedLandingSite"; visualCategoryNames[GeoDataPlacemark::RoboticRover] = "RoboticRover"; visualCategoryNames[GeoDataPlacemark::UnmannedSoftLandingSite] = "UnmannedSoftLandingSite"; visualCategoryNames[GeoDataPlacemark::UnmannedHardLandingSite] = "UnmannedHardLandingSite"; visualCategoryNames[GeoDataPlacemark::Bookmark] = "Bookmark"; visualCategoryNames[GeoDataPlacemark::NaturalWater] = "NaturalWater"; visualCategoryNames[GeoDataPlacemark::NaturalReef] = "NaturalReef"; visualCategoryNames[GeoDataPlacemark::NaturalWood] = "NaturalWood"; visualCategoryNames[GeoDataPlacemark::NaturalBeach] = "NaturalBeach"; visualCategoryNames[GeoDataPlacemark::NaturalWetland] = "NaturalWetland"; visualCategoryNames[GeoDataPlacemark::NaturalGlacier] = "NaturalGlacier"; visualCategoryNames[GeoDataPlacemark::NaturalIceShelf] = "NaturalIceShelf"; visualCategoryNames[GeoDataPlacemark::NaturalScrub] = "NaturalScrub"; visualCategoryNames[GeoDataPlacemark::NaturalCliff] = "NaturalCliff"; visualCategoryNames[GeoDataPlacemark::NaturalHeath] = "NaturalHeath"; visualCategoryNames[GeoDataPlacemark::HighwayTrafficSignals] = "HighwayTrafficSignals"; visualCategoryNames[GeoDataPlacemark::HighwaySteps] = "HighwaySteps"; visualCategoryNames[GeoDataPlacemark::HighwayUnknown] = "HighwayUnknown"; visualCategoryNames[GeoDataPlacemark::HighwayPath] = "HighwayPath"; visualCategoryNames[GeoDataPlacemark::HighwayFootway] = "HighwayFootway"; visualCategoryNames[GeoDataPlacemark::HighwayTrack] = "HighwayTrack"; visualCategoryNames[GeoDataPlacemark::HighwayPedestrian] = "HighwayPedestrian"; visualCategoryNames[GeoDataPlacemark::HighwayCycleway] = "HighwayCycleway"; visualCategoryNames[GeoDataPlacemark::HighwayService] = "HighwayService"; visualCategoryNames[GeoDataPlacemark::HighwayRoad] = "HighwayRoad"; visualCategoryNames[GeoDataPlacemark::HighwayResidential] = "HighwayResidential"; visualCategoryNames[GeoDataPlacemark::HighwayLivingStreet] = "HighwayLivingStreet"; visualCategoryNames[GeoDataPlacemark::HighwayUnclassified] = "HighwayUnclassified"; visualCategoryNames[GeoDataPlacemark::HighwayTertiaryLink] = "HighwayTertiaryLink"; visualCategoryNames[GeoDataPlacemark::HighwayTertiary] = "HighwayTertiary"; visualCategoryNames[GeoDataPlacemark::HighwaySecondaryLink] = "HighwaySecondaryLink"; visualCategoryNames[GeoDataPlacemark::HighwaySecondary] = "HighwaySecondary"; visualCategoryNames[GeoDataPlacemark::HighwayPrimaryLink] = "HighwayPrimaryLink"; visualCategoryNames[GeoDataPlacemark::HighwayPrimary] = "HighwayPrimary"; visualCategoryNames[GeoDataPlacemark::HighwayRaceway] = "HighwayRaceway"; visualCategoryNames[GeoDataPlacemark::HighwayTrunkLink] = "HighwayTrunkLink"; visualCategoryNames[GeoDataPlacemark::HighwayTrunk] = "HighwayTrunk"; visualCategoryNames[GeoDataPlacemark::HighwayMotorwayLink] = "HighwayMotorwayLink"; visualCategoryNames[GeoDataPlacemark::HighwayMotorway] = "HighwayMotorway"; visualCategoryNames[GeoDataPlacemark::HighwayCorridor] = "HighwayCorridor"; visualCategoryNames[GeoDataPlacemark::Building] = "Building"; visualCategoryNames[GeoDataPlacemark::AccomodationCamping] = "AccomodationCamping"; visualCategoryNames[GeoDataPlacemark::AccomodationHostel] = "AccomodationHostel"; visualCategoryNames[GeoDataPlacemark::AccomodationHotel] = "AccomodationHotel"; visualCategoryNames[GeoDataPlacemark::AccomodationMotel] = "AccomodationMotel"; visualCategoryNames[GeoDataPlacemark::AccomodationYouthHostel] = "AccomodationYouthHostel"; visualCategoryNames[GeoDataPlacemark::AccomodationGuestHouse] = "AccomodationGuestHouse"; visualCategoryNames[GeoDataPlacemark::AmenityLibrary] = "AmenityLibrary"; visualCategoryNames[GeoDataPlacemark::AmenityKindergarten] = "AmenityKindergarten"; visualCategoryNames[GeoDataPlacemark::EducationCollege] = "EducationCollege"; visualCategoryNames[GeoDataPlacemark::EducationSchool] = "EducationSchool"; visualCategoryNames[GeoDataPlacemark::EducationUniversity] = "EducationUniversity"; visualCategoryNames[GeoDataPlacemark::FoodBar] = "FoodBar"; visualCategoryNames[GeoDataPlacemark::FoodBiergarten] = "FoodBiergarten"; visualCategoryNames[GeoDataPlacemark::FoodCafe] = "FoodCafe"; visualCategoryNames[GeoDataPlacemark::FoodFastFood] = "FoodFastFood"; visualCategoryNames[GeoDataPlacemark::FoodPub] = "FoodPub"; visualCategoryNames[GeoDataPlacemark::FoodRestaurant] = "FoodRestaurant"; visualCategoryNames[GeoDataPlacemark::HealthDentist] = "HealthDentist"; visualCategoryNames[GeoDataPlacemark::HealthDoctors] = "HealthDoctors"; visualCategoryNames[GeoDataPlacemark::HealthHospital] = "HealthHospital"; visualCategoryNames[GeoDataPlacemark::HealthPharmacy] = "HealthPharmacy"; visualCategoryNames[GeoDataPlacemark::HealthVeterinary] = "HealthVeterinary"; visualCategoryNames[GeoDataPlacemark::MoneyAtm] = "MoneyAtm"; visualCategoryNames[GeoDataPlacemark::MoneyBank] = "MoneyBank"; visualCategoryNames[GeoDataPlacemark::AmenityEmbassy] = "AmenityEmbassy"; visualCategoryNames[GeoDataPlacemark::AmenityEmergencyPhone] = "AmenityEmergencyPhone"; visualCategoryNames[GeoDataPlacemark::AmenityMountainRescue] = "AmenityMountainRescue"; visualCategoryNames[GeoDataPlacemark::LeisureWaterPark] = "LeisureWaterPark"; visualCategoryNames[GeoDataPlacemark::AmenityCommunityCentre] = "AmenityCommunityCentre"; visualCategoryNames[GeoDataPlacemark::AmenityFountain] = "AmenityFountain"; visualCategoryNames[GeoDataPlacemark::AmenityNightClub] = "AmenityNightClub"; visualCategoryNames[GeoDataPlacemark::AmenityBench] = "AmenityBench"; visualCategoryNames[GeoDataPlacemark::AmenityCourtHouse] = "AmenityCourtHouse"; visualCategoryNames[GeoDataPlacemark::AmenityFireStation] = "AmenityFireStation"; visualCategoryNames[GeoDataPlacemark::AmenityHuntingStand] = "AmenityHuntingStand"; visualCategoryNames[GeoDataPlacemark::AmenityPolice] = "AmenityPolice"; visualCategoryNames[GeoDataPlacemark::AmenityPostBox] = "AmenityPostBox"; visualCategoryNames[GeoDataPlacemark::AmenityPostOffice] = "AmenityPostOffice"; visualCategoryNames[GeoDataPlacemark::AmenityPrison] = "AmenityPrison"; visualCategoryNames[GeoDataPlacemark::AmenityRecycling] = "AmenityRecycling"; visualCategoryNames[GeoDataPlacemark::AmenityShelter] = "AmenityShelter"; visualCategoryNames[GeoDataPlacemark::AmenityTelephone] = "AmenityTelephone"; visualCategoryNames[GeoDataPlacemark::AmenityToilets] = "AmenityToilets"; visualCategoryNames[GeoDataPlacemark::AmenityTownHall] = "AmenityTownHall"; visualCategoryNames[GeoDataPlacemark::AmenityWasteBasket] = "AmenityWasteBasket"; visualCategoryNames[GeoDataPlacemark::AmenityDrinkingWater] = "AmenityDrinkingWater"; visualCategoryNames[GeoDataPlacemark::AmenityGraveyard] = "AmenityGraveyard"; visualCategoryNames[GeoDataPlacemark::AmenityChargingStation] = "ChargingStation"; visualCategoryNames[GeoDataPlacemark::AmenityCarWash] = "CarWash"; visualCategoryNames[GeoDataPlacemark::AmenitySocialFacility] = "SocialFacility"; visualCategoryNames[GeoDataPlacemark::BarrierCityWall] = "BarrierCityWall"; visualCategoryNames[GeoDataPlacemark::BarrierGate] = "BarrierGate"; visualCategoryNames[GeoDataPlacemark::BarrierLiftGate] = "BarrierLiftGate"; visualCategoryNames[GeoDataPlacemark::BarrierWall] = "BarrierWall"; visualCategoryNames[GeoDataPlacemark::NaturalVolcano] = "NaturalVolcano"; visualCategoryNames[GeoDataPlacemark::NaturalPeak] = "NaturalPeak"; visualCategoryNames[GeoDataPlacemark::NaturalTree] = "NaturalTree"; visualCategoryNames[GeoDataPlacemark::NaturalCave] = "NaturalCave"; visualCategoryNames[GeoDataPlacemark::ShopBeverages] = "ShopBeverages"; visualCategoryNames[GeoDataPlacemark::ShopHifi] = "ShopHifi"; visualCategoryNames[GeoDataPlacemark::ShopSupermarket] = "ShopSupermarket"; visualCategoryNames[GeoDataPlacemark::ShopAlcohol] = "ShopAlcohol"; visualCategoryNames[GeoDataPlacemark::ShopBakery] = "ShopBakery"; visualCategoryNames[GeoDataPlacemark::ShopButcher] = "ShopButcher"; visualCategoryNames[GeoDataPlacemark::ShopConfectionery] = "ShopConfectionery"; visualCategoryNames[GeoDataPlacemark::ShopConvenience] = "ShopConvenience"; visualCategoryNames[GeoDataPlacemark::ShopGreengrocer] = "ShopGreengrocer"; visualCategoryNames[GeoDataPlacemark::ShopSeafood] = "ShopSeafood"; visualCategoryNames[GeoDataPlacemark::ShopDepartmentStore] = "ShopDepartmentStore"; visualCategoryNames[GeoDataPlacemark::ShopKiosk] = "ShopKiosk"; visualCategoryNames[GeoDataPlacemark::ShopBag] = "ShopBag"; visualCategoryNames[GeoDataPlacemark::ShopClothes] = "ShopClothes"; visualCategoryNames[GeoDataPlacemark::ShopFashion] = "ShopFashion"; visualCategoryNames[GeoDataPlacemark::ShopJewelry] = "ShopJewelry"; visualCategoryNames[GeoDataPlacemark::ShopShoes] = "ShopShoes"; visualCategoryNames[GeoDataPlacemark::ShopVarietyStore] = "ShopVarietyStore"; visualCategoryNames[GeoDataPlacemark::ShopBeauty] = "ShopBeauty"; visualCategoryNames[GeoDataPlacemark::ShopChemist] = "ShopChemist"; visualCategoryNames[GeoDataPlacemark::ShopCosmetics] = "ShopCosmetics"; visualCategoryNames[GeoDataPlacemark::ShopHairdresser] = "ShopHairdresser"; visualCategoryNames[GeoDataPlacemark::ShopOptician] = "ShopOptician"; visualCategoryNames[GeoDataPlacemark::ShopPerfumery] = "ShopPerfumery"; visualCategoryNames[GeoDataPlacemark::ShopDoitYourself] = "ShopDoitYourself"; visualCategoryNames[GeoDataPlacemark::ShopFlorist] = "ShopFlorist"; visualCategoryNames[GeoDataPlacemark::ShopHardware] = "ShopHardware"; visualCategoryNames[GeoDataPlacemark::ShopFurniture] = "ShopFurniture"; visualCategoryNames[GeoDataPlacemark::ShopElectronics] = "ShopElectronics"; visualCategoryNames[GeoDataPlacemark::ShopMobilePhone] = "ShopMobilePhone"; visualCategoryNames[GeoDataPlacemark::ShopBicycle] = "ShopBicycle"; visualCategoryNames[GeoDataPlacemark::ShopCar] = "ShopCar"; visualCategoryNames[GeoDataPlacemark::ShopCarRepair] = "ShopCarRepair"; visualCategoryNames[GeoDataPlacemark::ShopCarParts] = "ShopCarParts"; visualCategoryNames[GeoDataPlacemark::ShopMotorcycle] = "ShopMotorcycle"; visualCategoryNames[GeoDataPlacemark::ShopOutdoor] = "ShopOutdoor"; visualCategoryNames[GeoDataPlacemark::ShopSports] = "ShopSports"; visualCategoryNames[GeoDataPlacemark::ShopCopy] = "ShopCopy"; visualCategoryNames[GeoDataPlacemark::ShopArt] = "ShopArt"; visualCategoryNames[GeoDataPlacemark::ShopMusicalInstrument] = "ShopMusicalInstrument"; visualCategoryNames[GeoDataPlacemark::ShopPhoto] = "ShopPhoto"; visualCategoryNames[GeoDataPlacemark::ShopBook] = "ShopBook"; visualCategoryNames[GeoDataPlacemark::ShopGift] = "ShopGift"; visualCategoryNames[GeoDataPlacemark::ShopStationery] = "ShopStationery"; visualCategoryNames[GeoDataPlacemark::ShopLaundry] = "ShopLaundry"; visualCategoryNames[GeoDataPlacemark::ShopPet] = "ShopPet"; visualCategoryNames[GeoDataPlacemark::ShopToys] = "ShopToys"; visualCategoryNames[GeoDataPlacemark::ShopTravelAgency] = "ShopTravelAgency"; visualCategoryNames[GeoDataPlacemark::ShopDeli] = "ShopDeli"; visualCategoryNames[GeoDataPlacemark::ShopTobacco] = "ShopTobacco"; visualCategoryNames[GeoDataPlacemark::ShopTea] = "ShopTea"; visualCategoryNames[GeoDataPlacemark::Shop] = "Shop"; visualCategoryNames[GeoDataPlacemark::ManmadeBridge] = "ManmadeBridge"; visualCategoryNames[GeoDataPlacemark::ManmadeLighthouse] = "ManmadeLighthouse"; visualCategoryNames[GeoDataPlacemark::ManmadePier] = "ManmadePier"; visualCategoryNames[GeoDataPlacemark::ManmadeWaterTower] = "ManmadeWaterTower"; visualCategoryNames[GeoDataPlacemark::ManmadeWindMill] = "ManmadeWindMill"; visualCategoryNames[GeoDataPlacemark::TourismAttraction] = "TouristAttraction"; visualCategoryNames[GeoDataPlacemark::TourismArtwork] = "TouristArtwork"; visualCategoryNames[GeoDataPlacemark::HistoricArchaeologicalSite] = "HistoricArchaeologicalSite"; visualCategoryNames[GeoDataPlacemark::HistoricCastle] = "HistoricCastle"; visualCategoryNames[GeoDataPlacemark::HistoricMemorial] = "HistoricMemorial"; visualCategoryNames[GeoDataPlacemark::HistoricMonument] = "HistoricMonument"; visualCategoryNames[GeoDataPlacemark::AmenityCinema] = "TouristCinema"; visualCategoryNames[GeoDataPlacemark::TourismInformation] = "TouristInformation"; visualCategoryNames[GeoDataPlacemark::TourismMuseum] = "TouristMuseum"; visualCategoryNames[GeoDataPlacemark::HistoricRuins] = "TouristRuin"; visualCategoryNames[GeoDataPlacemark::AmenityTheatre] = "TouristTheatre"; visualCategoryNames[GeoDataPlacemark::TourismThemePark] = "TouristThemePark"; visualCategoryNames[GeoDataPlacemark::TourismViewPoint] = "TouristViewPoint"; visualCategoryNames[GeoDataPlacemark::TourismZoo] = "TouristZoo"; visualCategoryNames[GeoDataPlacemark::TourismAlpineHut] = "TouristAlpineHut"; visualCategoryNames[GeoDataPlacemark::TourismWildernessHut] = "TouristWildernessHut"; visualCategoryNames[GeoDataPlacemark::TransportAerodrome] = "TransportAerodrome"; visualCategoryNames[GeoDataPlacemark::TransportHelipad] = "TransportHelipad"; visualCategoryNames[GeoDataPlacemark::TransportAirportTerminal] = "TransportAirportTerminal"; visualCategoryNames[GeoDataPlacemark::TransportAirportGate] = "TransportAirportGate"; visualCategoryNames[GeoDataPlacemark::TransportAirportRunway] = "TransportAirportRunway"; visualCategoryNames[GeoDataPlacemark::TransportAirportTaxiway] = "TransportAirportTaxiway"; visualCategoryNames[GeoDataPlacemark::TransportAirportApron] = "TransportAirportApron"; visualCategoryNames[GeoDataPlacemark::TransportBusStation] = "TransportBusStation"; visualCategoryNames[GeoDataPlacemark::TransportBusStop] = "TransportBusStop"; visualCategoryNames[GeoDataPlacemark::TransportCarShare] = "TransportCarShare"; visualCategoryNames[GeoDataPlacemark::TransportFuel] = "TransportFuel"; visualCategoryNames[GeoDataPlacemark::TransportParking] = "TransportParking"; visualCategoryNames[GeoDataPlacemark::TransportParkingSpace] = "TransportParkingSpace"; visualCategoryNames[GeoDataPlacemark::TransportPlatform] = "TransportPlatform"; visualCategoryNames[GeoDataPlacemark::TransportRentalBicycle] = "TransportRentalBicycle"; visualCategoryNames[GeoDataPlacemark::TransportRentalCar] = "TransportRentalCar"; visualCategoryNames[GeoDataPlacemark::TransportRentalSki] = "TransportRentalSki"; visualCategoryNames[GeoDataPlacemark::TransportTaxiRank] = "TransportTaxiRank"; visualCategoryNames[GeoDataPlacemark::TransportTrainStation] = "TransportTrainStation"; visualCategoryNames[GeoDataPlacemark::TransportTramStop] = "TransportTramStop"; visualCategoryNames[GeoDataPlacemark::TransportSpeedCamera] = "TransportSpeedCamera"; visualCategoryNames[GeoDataPlacemark::TransportBicycleParking] = "TransportBicycleParking"; visualCategoryNames[GeoDataPlacemark::TransportMotorcycleParking] = "TransportMotorcycleParking"; visualCategoryNames[GeoDataPlacemark::TransportSubwayEntrance] = "TransportSubwayEntrance"; visualCategoryNames[GeoDataPlacemark::ReligionPlaceOfWorship] = "ReligionPlaceOfWorship"; visualCategoryNames[GeoDataPlacemark::ReligionBahai] = "ReligionBahai"; visualCategoryNames[GeoDataPlacemark::ReligionBuddhist] = "ReligionBuddhist"; visualCategoryNames[GeoDataPlacemark::ReligionChristian] = "ReligionChristian"; visualCategoryNames[GeoDataPlacemark::ReligionMuslim] = "ReligionMuslim"; visualCategoryNames[GeoDataPlacemark::ReligionHindu] = "ReligionHindu"; visualCategoryNames[GeoDataPlacemark::ReligionJain] = "ReligionJain"; visualCategoryNames[GeoDataPlacemark::ReligionJewish] = "ReligionJewish"; visualCategoryNames[GeoDataPlacemark::ReligionShinto] = "ReligionShinto"; visualCategoryNames[GeoDataPlacemark::ReligionSikh] = "ReligionSikh"; visualCategoryNames[GeoDataPlacemark::LeisureGolfCourse] = "LeisureGolfCourse"; visualCategoryNames[GeoDataPlacemark::LeisureMarina] = "LeisureMarina"; visualCategoryNames[GeoDataPlacemark::LeisurePark] = "LeisurePark"; visualCategoryNames[GeoDataPlacemark::LeisurePlayground] = "LeisurePlayground"; visualCategoryNames[GeoDataPlacemark::LeisurePitch] = "LeisurePitch"; visualCategoryNames[GeoDataPlacemark::LeisureSportsCentre] = "LeisureSportsCentre"; visualCategoryNames[GeoDataPlacemark::LeisureStadium] = "LeisureStadium"; visualCategoryNames[GeoDataPlacemark::LeisureTrack] = "LeisureTrack"; visualCategoryNames[GeoDataPlacemark::LeisureSwimmingPool] = "LeisureSwimmingPool"; visualCategoryNames[GeoDataPlacemark::LeisureMinigolfCourse] = "LeisureMinigolfCourse"; visualCategoryNames[GeoDataPlacemark::LanduseAllotments] = "LanduseAllotments"; visualCategoryNames[GeoDataPlacemark::LanduseBasin] = "LanduseBasin"; visualCategoryNames[GeoDataPlacemark::LanduseCemetery] = "LanduseCemetery"; visualCategoryNames[GeoDataPlacemark::LanduseCommercial] = "LanduseCommercial"; visualCategoryNames[GeoDataPlacemark::LanduseConstruction] = "LanduseConstruction"; visualCategoryNames[GeoDataPlacemark::LanduseFarmland] = "LanduseFarmland"; visualCategoryNames[GeoDataPlacemark::LanduseFarmyard] = "LanduseFarmyard"; visualCategoryNames[GeoDataPlacemark::LanduseGarages] = "LanduseGarages"; visualCategoryNames[GeoDataPlacemark::LanduseGrass] = "LanduseGrass"; visualCategoryNames[GeoDataPlacemark::LanduseIndustrial] = "LanduseIndustrial"; visualCategoryNames[GeoDataPlacemark::LanduseLandfill] = "LanduseLandfill"; visualCategoryNames[GeoDataPlacemark::LanduseMeadow] = "LanduseMeadow"; visualCategoryNames[GeoDataPlacemark::LanduseMilitary] = "LanduseMilitary"; visualCategoryNames[GeoDataPlacemark::LanduseQuarry] = "LanduseQuarry"; visualCategoryNames[GeoDataPlacemark::LanduseRailway] = "LanduseRailway"; visualCategoryNames[GeoDataPlacemark::LanduseReservoir] = "LanduseReservoir"; visualCategoryNames[GeoDataPlacemark::LanduseResidential] = "LanduseResidential"; visualCategoryNames[GeoDataPlacemark::LanduseRetail] = "LanduseRetail"; visualCategoryNames[GeoDataPlacemark::LanduseOrchard] = "LanduseOrchard"; visualCategoryNames[GeoDataPlacemark::LanduseVineyard] = "LanduseVineyard"; visualCategoryNames[GeoDataPlacemark::RailwayRail] = "RailwayRail"; visualCategoryNames[GeoDataPlacemark::RailwayNarrowGauge] = "RailwayNarrowGauge"; visualCategoryNames[GeoDataPlacemark::RailwayTram] = "RailwayTram"; visualCategoryNames[GeoDataPlacemark::RailwayLightRail] = "RailwayLightRail"; visualCategoryNames[GeoDataPlacemark::RailwayAbandoned] = "RailwayAbandoned"; visualCategoryNames[GeoDataPlacemark::RailwaySubway] = "RailwaySubway"; visualCategoryNames[GeoDataPlacemark::RailwayPreserved] = "RailwayPreserved"; visualCategoryNames[GeoDataPlacemark::RailwayMiniature] = "RailwayMiniature"; visualCategoryNames[GeoDataPlacemark::RailwayConstruction] = "RailwayConstruction"; visualCategoryNames[GeoDataPlacemark::RailwayMonorail] = "RailwayMonorail"; visualCategoryNames[GeoDataPlacemark::RailwayFunicular] = "RailwayFunicular"; visualCategoryNames[GeoDataPlacemark::PowerTower] = "PowerTower"; visualCategoryNames[GeoDataPlacemark::AerialwayStation] = "AerialwayStation"; visualCategoryNames[GeoDataPlacemark::AerialwayPylon] = "AerialwayPylon"; visualCategoryNames[GeoDataPlacemark::AerialwayCableCar] = "AerialwayCableCar"; visualCategoryNames[GeoDataPlacemark::AerialwayGondola] = "AerialwayGondola"; visualCategoryNames[GeoDataPlacemark::AerialwayChairLift] = "AerialwayChairLift"; visualCategoryNames[GeoDataPlacemark::AerialwayMixedLift] = "AerialwayMixedLift"; visualCategoryNames[GeoDataPlacemark::AerialwayDragLift] = "AerialwayDragLift"; visualCategoryNames[GeoDataPlacemark::AerialwayTBar] = "AerialwayTBar"; visualCategoryNames[GeoDataPlacemark::AerialwayJBar] = "AerialwayJBar"; visualCategoryNames[GeoDataPlacemark::AerialwayPlatter] = "AerialwayPlatter"; visualCategoryNames[GeoDataPlacemark::AerialwayRopeTow] = "AerialwayRopeTow"; visualCategoryNames[GeoDataPlacemark::AerialwayMagicCarpet] = "AerialwayMagicCarpet"; visualCategoryNames[GeoDataPlacemark::AerialwayZipLine] = "AerialwayZipLine"; visualCategoryNames[GeoDataPlacemark::AerialwayGoods] = "AerialwayGoods"; visualCategoryNames[GeoDataPlacemark::PisteDownhill] = "PisteDownhill"; visualCategoryNames[GeoDataPlacemark::PisteNordic] = "PisteNordic"; visualCategoryNames[GeoDataPlacemark::PisteSkitour] = "PisteSkitour"; visualCategoryNames[GeoDataPlacemark::PisteSled] = "PisteSled"; visualCategoryNames[GeoDataPlacemark::PisteHike] = "PisteHike"; visualCategoryNames[GeoDataPlacemark::PisteSleigh] = "PisteSleigh"; visualCategoryNames[GeoDataPlacemark::PisteIceSkate] = "PisteIceSkate"; visualCategoryNames[GeoDataPlacemark::PisteSnowPark] = "PisteSnowPark"; visualCategoryNames[GeoDataPlacemark::PistePlayground] = "PistePlayground"; visualCategoryNames[GeoDataPlacemark::PisteSkiJump] = "PisteSkiJump"; visualCategoryNames[GeoDataPlacemark::Satellite] = "Satellite"; visualCategoryNames[GeoDataPlacemark::Landmass] = "Landmass"; visualCategoryNames[GeoDataPlacemark::UrbanArea] = "UrbanArea"; visualCategoryNames[GeoDataPlacemark::InternationalDateLine] = "InternationalDateLine"; visualCategoryNames[GeoDataPlacemark::Bathymetry] = "Bathymetry"; visualCategoryNames[GeoDataPlacemark::AdminLevel1] = "AdminLevel1"; visualCategoryNames[GeoDataPlacemark::AdminLevel2] = "AdminLevel2"; visualCategoryNames[GeoDataPlacemark::AdminLevel3] = "AdminLevel3"; visualCategoryNames[GeoDataPlacemark::AdminLevel4] = "AdminLevel4"; visualCategoryNames[GeoDataPlacemark::AdminLevel5] = "AdminLevel5"; visualCategoryNames[GeoDataPlacemark::AdminLevel6] = "AdminLevel6"; visualCategoryNames[GeoDataPlacemark::AdminLevel7] = "AdminLevel7"; visualCategoryNames[GeoDataPlacemark::AdminLevel8] = "AdminLevel8"; visualCategoryNames[GeoDataPlacemark::AdminLevel9] = "AdminLevel9"; visualCategoryNames[GeoDataPlacemark::AdminLevel10] = "AdminLevel10"; visualCategoryNames[GeoDataPlacemark::AdminLevel11] = "AdminLevel11"; visualCategoryNames[GeoDataPlacemark::BoundaryMaritime] = "BoundaryMaritime"; visualCategoryNames[GeoDataPlacemark::WaterwayCanal] = "WaterwayCanal"; visualCategoryNames[GeoDataPlacemark::WaterwayDitch] = "WaterwayDitch"; visualCategoryNames[GeoDataPlacemark::WaterwayDrain] = "WaterwayDrain"; visualCategoryNames[GeoDataPlacemark::WaterwayStream] = "WaterwayStream"; visualCategoryNames[GeoDataPlacemark::WaterwayRiver] = "WaterwayRiver"; visualCategoryNames[GeoDataPlacemark::WaterwayWeir] = "WaterwayWeir"; visualCategoryNames[GeoDataPlacemark::CrossingIsland] = "CrossingIsland"; visualCategoryNames[GeoDataPlacemark::CrossingRailway] = "CrossingRailway"; visualCategoryNames[GeoDataPlacemark::CrossingSignals] = "CrossingSignals"; visualCategoryNames[GeoDataPlacemark::CrossingZebra] = "CrossingZebra"; visualCategoryNames[GeoDataPlacemark::LastIndex] = "LastIndex"; } Q_ASSERT(visualCategoryNames.contains(category)); return visualCategoryNames[category]; } QHash StyleBuilder::osmTagMapping() { Private::initializeOsmVisualCategories(); return Private::s_visualCategories; } QStringList StyleBuilder::shopValues() { // from https://taginfo.openstreetmap.org/keys/building#values static const QStringList osmShopValues = QStringList() << "cheese" << "chocolate" << "coffee" << "dairy" << "farm" << "pasta" << "pastry" << "wine" << "general" << "mall" << "baby_goods" << "boutique" << "fabric" << "leather" << "tailor" << "watches" << "charity" << "second_hand" << "erotic" << "hearing_aids" << "herbalist" << "massage" << "medical_supply" << "tattoo" << "bathroom_furnishing" << "electrical" << "energy" << "furnace" << "garden_centre" << "garden_furniture" << "gas" << "glaziery" << "houseware" << "locksmith" << "paint" << "trade" << "antiques" << "bed" << "candles" << "carpet" << "curtain" << "interior_decoration" << "kitchen" << "lamps" << "window_blind" << "computer" << "radiotechnics" << "vacuum_cleaner" << "fishing" << "free_flying" << "hunting" << "outdoor" << "scuba_diving" << "sports" << "tyres" << "swimming_pool" << "art" << "craft" << "frame" << "games" << "model" << "music" << "trophy" << "video" << "video_games" << "anime" << "ticket" << "copyshop" << "dry_cleaning" << "e-cigarette" << "funeral_directors" << "money_lender" << "pawnbroker" << "pyrotechnics" << "religion" << "storage_rental" << "weapons" << "user defined"; return osmShopValues; } QSet StyleBuilder::buildingTags() { static const QString building = QStringLiteral("building"); // from https://taginfo.openstreetmap.org/keys/building#values static const QSet osmBuildingTags = QSet() << OsmTag(building, "yes") << OsmTag(building, "house") << OsmTag(building, "residential") << OsmTag(building, "garage") << OsmTag(building, "apartments") << OsmTag(building, "hut") << OsmTag(building, "industrial") << OsmTag(building, "detached") << OsmTag(building, "roof") << OsmTag(building, "garages") << OsmTag(building, "commercial") << OsmTag(building, "terrace") << OsmTag(building, "shed") << OsmTag(building, "school") << OsmTag(building, "retail") << OsmTag(building, "farm_auxiliary") << OsmTag(building, "church") << OsmTag(building, "cathedral") << OsmTag(building, "greenhouse") << OsmTag(building, "barn") << OsmTag(building, "service") << OsmTag(building, "manufacture") << OsmTag(building, "construction") << OsmTag(building, "cabin") << OsmTag(building, "farm") << OsmTag(building, "warehouse") << OsmTag(building, "House") << OsmTag(building, "office") << OsmTag(building, "civic") << OsmTag(building, "Residential") << OsmTag(building, "hangar") << OsmTag(building, "public") << OsmTag(building, "university") << OsmTag(building, "hospital") << OsmTag(building, "chapel") << OsmTag(building, "hotel") << OsmTag(building, "train_station") << OsmTag(building, "dormitory") << OsmTag(building, "kindergarten") << OsmTag(building, "stable") << OsmTag(building, "storage_tank") << OsmTag(building, "shop") << OsmTag(building, "college") << OsmTag(building, "supermarket") << OsmTag(building, "factory") << OsmTag(building, "bungalow") << OsmTag(building, "tower") << OsmTag(building, "silo") << OsmTag(building, "storage") << OsmTag(building, "station") << OsmTag(building, "education") << OsmTag(building, "carport") << OsmTag(building, "houseboat") << OsmTag(building, "castle") << OsmTag(building, "social_facility") << OsmTag(building, "water_tower") << OsmTag(building, "container") << OsmTag(building, "exhibition_hall") << OsmTag(building, "monastery") << OsmTag(building, "bunker") << OsmTag(building, "shelter") << OsmTag("building:part", "yes") << OsmTag("building:part", "antenna"); return osmBuildingTags; } GeoDataPlacemark::GeoDataVisualCategory StyleBuilder::determineVisualCategory(const OsmPlacemarkData &osmData) { QString const yes(QStringLiteral("yes")); if (osmData.containsTagKey(QStringLiteral("area:highway")) || // Not supported yet osmData.containsTag(QStringLiteral("boundary"), QStringLiteral("protected_area")) || // Not relevant for the default map osmData.containsTag(QStringLiteral("boundary"), QStringLiteral("postal_code")) || osmData.containsTag(QStringLiteral("boundary"), QStringLiteral("aerial_views")) || // Created by OSM editor(s) application for digitalization osmData.containsTagKey(QStringLiteral("closed:highway")) || osmData.containsTagKey(QStringLiteral("abandoned:highway")) || osmData.containsTagKey(QStringLiteral("abandoned:natural")) || osmData.containsTagKey(QStringLiteral("abandoned:building")) || osmData.containsTagKey(QStringLiteral("abandoned:leisure")) || osmData.containsTagKey(QStringLiteral("disused:highway")) || osmData.containsTag(QStringLiteral("highway"), QStringLiteral("razed")) || osmData.containsTag(QStringLiteral("piste:abandoned"), yes)) { return GeoDataPlacemark::None; } if (osmData.containsTag(QStringLiteral("building"), yes)) { return GeoDataPlacemark::Building; } if (osmData.containsTag(QStringLiteral("historic"), QStringLiteral("castle")) && osmData.containsTag(QStringLiteral("castle_type"), QStringLiteral("kremlin"))) { return GeoDataPlacemark::None; } if (osmData.containsTag(QStringLiteral("natural"), QStringLiteral("glacier")) && osmData.containsTag(QStringLiteral("glacier:type"), QStringLiteral("shelf"))) { return GeoDataPlacemark::NaturalIceShelf; } if (osmData.containsTag(QStringLiteral("highway"), QStringLiteral("crossing"))) { QStringList const crossings = osmData.tagValue(QStringLiteral("crossing")).split(';'); QString const crossingRef = osmData.tagValue(QStringLiteral("crossing_ref")); if (crossingRef == QStringLiteral("zebra") || crossingRef == QStringLiteral("tiger") || crossings.contains(QStringLiteral("zebra")) || crossings.contains(QStringLiteral("tiger"))) { return GeoDataPlacemark::CrossingZebra; } else if (crossingRef == QStringLiteral("toucan") || crossingRef == QStringLiteral("pelican") || crossings.contains(QStringLiteral("traffic_signals")) || crossings.contains(QStringLiteral("toucan")) || crossings.contains(QStringLiteral("pelican"))) { return GeoDataPlacemark::CrossingSignals; } else if (crossings.contains(QStringLiteral("island"))) { return GeoDataPlacemark::CrossingIsland; } } if (osmData.containsTag(QStringLiteral("railway"), QStringLiteral("crossing")) || osmData.containsTag(QStringLiteral("railway"), QStringLiteral("level_crossing"))) { return GeoDataPlacemark::CrossingRailway; } Private::initializeOsmVisualCategories(); auto const pisteType = osmData.tagValue(QStringLiteral("piste:type")); if (!pisteType.isEmpty()) { auto const tag = OsmTag(QStringLiteral("piste:type"), pisteType); auto category = Private::s_visualCategories.value(tag, GeoDataPlacemark::None); if (category != GeoDataPlacemark::None) { return category; } } QString const capital(QStringLiteral("capital")); QString const admin_level(QStringLiteral("admin_level")); // National capitals have admin_level=2 // More at http://wiki.openstreetmap.org/wiki/Key:capital#Using_relations_for_capitals QString const national_level(QStringLiteral("2")); for (auto iter = osmData.tagsBegin(), end = osmData.tagsEnd(); iter != end; ++iter) { const auto tag = OsmTag(iter.key(), iter.value()); GeoDataPlacemark::GeoDataVisualCategory category = Private::s_visualCategories.value(tag, GeoDataPlacemark::None); if (category != GeoDataPlacemark::None) { if (category == GeoDataPlacemark::PlaceCity && osmData.containsTag(admin_level, national_level)) { category = GeoDataPlacemark::PlaceCityNationalCapital; } else if (category == GeoDataPlacemark::PlaceCity && osmData.containsTag(capital, yes)) { category = GeoDataPlacemark::PlaceCityCapital; } else if (category == GeoDataPlacemark::PlaceTown && osmData.containsTag(admin_level, national_level)) { category = GeoDataPlacemark::PlaceTownNationalCapital; } else if (category == GeoDataPlacemark::PlaceTown && osmData.containsTag(capital, yes)) { category = GeoDataPlacemark::PlaceTownCapital; } else if (category == GeoDataPlacemark::PlaceVillage && osmData.containsTag(admin_level, national_level)) { category = GeoDataPlacemark::PlaceVillageNationalCapital; } else if (category == GeoDataPlacemark::PlaceVillage && osmData.containsTag(capital, yes)) { category = GeoDataPlacemark::PlaceVillageCapital; } } if (category != GeoDataPlacemark::None) { return category; } } return GeoDataPlacemark::None; } StyleParameters::StyleParameters(const GeoDataPlacemark *placemark_, int tileLevel_) : placemark(placemark_), tileLevel(tileLevel_), relation(nullptr) { // nothing to do } } diff --git a/src/lib/marble/TextureColorizer.cpp b/src/lib/marble/TextureColorizer.cpp index 0e041e24c..25c559b8f 100644 --- a/src/lib/marble/TextureColorizer.cpp +++ b/src/lib/marble/TextureColorizer.cpp @@ -1,376 +1,369 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2006-2007 Torsten Rahn // Copyright 2007 Inge Wallin // Copyright 2008 Carlos Licea // Copyright 2012 Cezar Mocan // #include "TextureColorizer.h" #include #include #include #include #include #include #include #include #include #include "MarbleGlobal.h" #include "GeoPainter.h" #include "MarbleDebug.h" #include "ViewParams.h" #include "ViewportParams.h" #include "MathHelper.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" #include "GeoDataFeature.h" -#include "GeoDataTypes.h" #include "GeoDataPlacemark.h" #include "GeoDataDocument.h" #include "AbstractProjection.h" namespace Marble { // 4 uchar long queue class EmbossFifo { public: EmbossFifo() : data( 0 ) {} inline uchar head() const { // return least significant byte as head of queue return data & 0x000000FF; } inline void enqueue(uchar value) { // drop current head by shifting by one byte // and append new value as most significant byte to queue data = ((data >> 8) & 0x00FFFFFF) | (value << 24); } private: // 4 byte long queue quint32 data; }; TextureColorizer::TextureColorizer( const QString &seafile, const QString &landfile ) : m_showRelief( false ), m_landColor(qRgb( 255, 0, 0 ) ), m_seaColor( qRgb( 0, 255, 0 ) ) { QTime t; t.start(); QImage gradientImage ( 256, 1, QImage::Format_RGB32 ); QPainter gradientPainter; gradientPainter.begin( &gradientImage ); gradientPainter.setPen( Qt::NoPen ); int shadingStart = 120; QImage shadingImage ( 16, 1, QImage::Format_RGB32 ); QPainter shadingPainter; shadingPainter.begin( &shadingImage ); shadingPainter.setPen( Qt::NoPen ); int offset = 0; QStringList filelist; filelist << seafile << landfile; for ( const QString &filename: filelist ) { QLinearGradient gradient( 0, 0, 256, 0 ); QFile file( filename ); file.open( QIODevice::ReadOnly ); QTextStream stream( &file ); // read the data from the file QString evalstrg; while ( !stream.atEnd() ) { stream >> evalstrg; if (!evalstrg.isEmpty() && evalstrg.contains(QLatin1Char('='))) { QString colorValue = evalstrg.left(evalstrg.indexOf(QLatin1Char('='))); QString colorPosition = evalstrg.mid(evalstrg.indexOf(QLatin1Char('=')) + 1); gradient.setColorAt( colorPosition.toDouble(), QColor( colorValue ) ); } } gradientPainter.setBrush( gradient ); gradientPainter.drawRect( 0, 0, 256, 1 ); QLinearGradient shadeGradient( - shadingStart, 0, 256 - shadingStart, 0 ); shadeGradient.setColorAt(0.00, QColor(Qt::white)); shadeGradient.setColorAt(0.15, QColor(Qt::white)); shadeGradient.setColorAt(0.75, QColor(Qt::black)); shadeGradient.setColorAt(1.00, QColor(Qt::black)); const QRgb * gradientScanLine = (QRgb*)( gradientImage.scanLine( 0 ) ); const QRgb * shadingScanLine = (QRgb*)( shadingImage.scanLine( 0 ) ); for ( int i = 0; i < 256; ++i ) { QRgb shadeColor = *(gradientScanLine + i ); shadeGradient.setColorAt(0.496, shadeColor); shadeGradient.setColorAt(0.504, shadeColor); shadingPainter.setBrush( shadeGradient ); shadingPainter.drawRect( 0, 0, 16, 1 ); // populate texturepalette[][] for ( int j = 0; j < 16; ++j ) { texturepalette[j][offset + i] = *(shadingScanLine + j ); } } offset += 256; } shadingPainter.end(); // Need to explicitly tell painter lifetime to avoid crash gradientPainter.end(); // on some systems. mDebug() << Q_FUNC_INFO << "Time elapsed:" << t.elapsed() << "ms"; } void TextureColorizer::addSeaDocument( const GeoDataDocument *seaDocument ) { m_seaDocuments.append( seaDocument ); } void TextureColorizer::addLandDocument( const GeoDataDocument *landDocument ) { m_landDocuments.append( landDocument ); } void TextureColorizer::setShowRelief( bool show ) { m_showRelief = show; } // This function takes two images, both in viewParams: // - The coast image, which has a number of colors where each color // represents a sort of terrain (ex: land/sea) // - The canvas image, which has a gray scale image, often // representing a height field. // // It then uses the values of the pixels in the coast image to select // a color map. The value of the pixel in the canvas image is used as // an index into the selected color map and the resulting color is // written back to the canvas image. This way we can have different // color schemes for land and water. // // In addition to this, a simple form of bump mapping is performed to // increase the illusion of height differences (see the variable // showRelief). // void TextureColorizer::drawIndividualDocument( GeoPainter *painter, const GeoDataDocument *document ) { QVector::ConstIterator i = document->constBegin(); QVector::ConstIterator end = document->constEnd(); for ( ; i != end; ++i ) { - if ( (*i)->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - - const GeoDataPlacemark *placemark = static_cast( *i ); - - if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { - const GeoDataLineString *child = static_cast( placemark->geometry() ); + if (const GeoDataPlacemark *placemark = geodata_cast(*i)) { + if (const GeoDataLineString *child = geodata_cast(placemark->geometry())) { const GeoDataLinearRing ring( *child ); painter->drawPolygon( ring ); } - if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { - const GeoDataPolygon *child = static_cast( placemark->geometry() ); + if (const GeoDataPolygon *child = geodata_cast(placemark->geometry())) { painter->drawPolygon( *child ); } - if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType ) { - const GeoDataLinearRing *child = static_cast( placemark->geometry() ); + if (const GeoDataLinearRing *child = geodata_cast(placemark->geometry())) { painter->drawPolygon( *child ); } } } } void TextureColorizer::drawTextureMap( GeoPainter *painter ) { for( const GeoDataDocument *doc: m_landDocuments ) { painter->setPen( QPen( Qt::NoPen ) ); painter->setBrush( QBrush( m_landColor ) ); drawIndividualDocument( painter, doc ); } for( const GeoDataDocument *doc: m_seaDocuments ) { if ( doc->isVisible() ) { painter->setPen( Qt::NoPen ); painter->setBrush( QBrush( m_seaColor ) ); drawIndividualDocument( painter, doc ); } } } void TextureColorizer::colorize( QImage *origimg, const ViewportParams *viewport, MapQuality mapQuality ) { if ( m_coastImage.size() != viewport->size() ) m_coastImage = QImage( viewport->size(), QImage::Format_RGB32 ); // update coast image m_coastImage.fill( QColor( 0, 0, 255, 0).rgb() ); const bool antialiased = mapQuality == HighQuality || mapQuality == PrintQuality; GeoPainter painter( &m_coastImage, viewport, mapQuality ); painter.setRenderHint( QPainter::Antialiasing, antialiased ); drawTextureMap( &painter ); const qint64 radius = viewport->radius() * viewport->currentProjection()->clippingRadius(); const int imgheight = origimg->height(); const int imgwidth = origimg->width(); const int imgrx = imgwidth / 2; const int imgry = imgheight / 2; // This variable is not used anywhere.. const int imgradius = imgrx * imgrx + imgry * imgry; int bump = 8; if ( radius * radius > imgradius || !viewport->currentProjection()->isClippedToSphere() ) { int yTop = 0; int yBottom = imgheight; if( !viewport->currentProjection()->isClippedToSphere() && !viewport->currentProjection()->traversablePoles() ) { qreal realYTop, realYBottom, dummyX; GeoDataCoordinates yNorth(0, viewport->currentProjection()->maxLat(), 0); GeoDataCoordinates ySouth(0, viewport->currentProjection()->minLat(), 0); viewport->screenCoordinates(yNorth, dummyX, realYTop ); viewport->screenCoordinates(ySouth, dummyX, realYBottom ); yTop = qBound(qreal(0.0), realYTop, qreal(imgheight)); yBottom = qBound(qreal(0.0), realYBottom, qreal(imgheight)); } const int itEnd = yBottom; for (int y = yTop; y < itEnd; ++y) { QRgb *writeData = (QRgb*)( origimg->scanLine( y ) ); const QRgb *coastData = (QRgb*)( m_coastImage.scanLine( y ) ); uchar *readDataStart = origimg->scanLine( y ); const uchar *readDataEnd = readDataStart + imgwidth*4; EmbossFifo emboss; for ( uchar* readData = readDataStart; readData < readDataEnd; readData += 4, ++writeData, ++coastData ) { // Cheap Emboss / Bumpmapping uchar& grey = *readData; // qBlue(*data); if ( m_showRelief ) { emboss.enqueue(grey); bump = ( emboss.head() + 8 - grey ); if (bump < 0) { bump = 0; } else if (bump > 15) { bump = 15; } } setPixel( coastData, writeData, bump, grey ); } } } else { int yTop = ( imgry-radius < 0 ) ? 0 : imgry-radius; const int yBottom = ( yTop == 0 ) ? imgheight : imgry + radius; EmbossFifo emboss; for ( int y = yTop; y < yBottom; ++y ) { const int dy = imgry - y; int rx = (int)sqrt( (qreal)( radius * radius - dy * dy ) ); int xLeft = 0; int xRight = imgwidth; if ( imgrx-rx > 0 ) { xLeft = imgrx - rx; xRight = imgrx + rx; } QRgb *writeData = (QRgb*)( origimg->scanLine( y ) ) + xLeft; const QRgb *coastData = (QRgb*)( m_coastImage.scanLine( y ) ) + xLeft; uchar *readDataStart = origimg->scanLine( y ) + xLeft * 4; const uchar *readDataEnd = origimg->scanLine( y ) + xRight * 4; for ( uchar* readData = readDataStart; readData < readDataEnd; readData += 4, ++writeData, ++coastData ) { // Cheap Emboss / Bumpmapping uchar& grey = *readData; // qBlue(*data); if ( m_showRelief ) { emboss.enqueue(grey); bump = ( emboss.head() + 16 - grey ) >> 1; if (bump < 0) { bump = 0; } else if (bump > 15) { bump = 15; } } setPixel( coastData, writeData, bump, grey ); } } } } void TextureColorizer::setPixel( const QRgb *coastData, QRgb *writeData, int bump, uchar grey ) { int alpha = qRed( *coastData ); if ( alpha == 255 ) *writeData = texturepalette[bump][grey + 0x100]; else if( alpha == 0 ){ *writeData = texturepalette[bump][grey]; } else { qreal c = 1.0 / 255.0; QRgb landcolor = (QRgb)(texturepalette[bump][grey + 0x100]); QRgb watercolor = (QRgb)(texturepalette[bump][grey]); *writeData = qRgb( (int) ( c * ( alpha * qRed( landcolor ) + ( 255 - alpha ) * qRed( watercolor ) ) ), (int) ( c * ( alpha * qGreen( landcolor ) + ( 255 - alpha ) * qGreen( watercolor ) ) ), (int) ( c * ( alpha * qBlue( landcolor ) + ( 255 - alpha ) * qBlue( watercolor ) ) ) ); } } } diff --git a/src/lib/marble/TourControlEditWidget.cpp b/src/lib/marble/TourControlEditWidget.cpp index cad4a54a6..d9983d462 100644 --- a/src/lib/marble/TourControlEditWidget.cpp +++ b/src/lib/marble/TourControlEditWidget.cpp @@ -1,89 +1,89 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2013 Mihail Ivchenko // Copyright 2014 Sanjiban Bairagya // Copyright 2014 Illya Kovalevskyy // #include #include #include #include #include "TourControlEditWidget.h" #include "MarblePlacemarkModel.h" -#include "GeoDataTypes.h" #include "GeoDataTourControl.h" namespace Marble { TourControlEditWidget::TourControlEditWidget( const QModelIndex &index, QWidget *parent ) : QWidget( parent ), m_index( index ), m_radio_play( new QRadioButton ), m_radio_pause( new QRadioButton ), m_button( new QToolButton ) { QHBoxLayout *layout = new QHBoxLayout; layout->setSpacing( 5 ); QLabel* iconLabel = new QLabel; iconLabel->setPixmap(QPixmap(QStringLiteral(":/marble/media-playback-pause.png"))); layout->addWidget( iconLabel ); layout->addWidget( m_radio_play ); m_radio_play->setText( tr( "Play" ) ); layout->addWidget( m_radio_pause ); m_radio_pause->setText( tr( "Pause" ) ); if( tourControlElement()->playMode() == GeoDataTourControl::Play ){ m_radio_play->setChecked( true ); }else{ m_radio_pause->setChecked( true ); } m_button->setIcon(QIcon(QStringLiteral(":/marble/document-save.png"))); connect(m_button, SIGNAL(clicked()), this, SLOT(save())); layout->addWidget( m_button ); setLayout( layout ); } bool TourControlEditWidget::editable() const { return m_button->isEnabled(); } void TourControlEditWidget::setEditable( bool editable ) { m_button->setEnabled( editable ); } void TourControlEditWidget::save() { if ( m_radio_play->isChecked() ) { tourControlElement()->setPlayMode( GeoDataTourControl::Play ); } else { tourControlElement()->setPlayMode( GeoDataTourControl::Pause ); } emit editingDone(m_index); } GeoDataTourControl* TourControlEditWidget::tourControlElement() { GeoDataObject *object = qvariant_cast(m_index.data( MarblePlacemarkModel::ObjectPointerRole ) ); Q_ASSERT( object ); - Q_ASSERT( object->nodeType() == GeoDataTypes::GeoDataTourControlType ); - return static_cast( object ); + auto tourControl = geodata_cast(object); + Q_ASSERT(tourControl); + return tourControl; } } // namespace Marble #include "moc_TourControlEditWidget.cpp" diff --git a/src/lib/marble/TourItemDelegate.cpp b/src/lib/marble/TourItemDelegate.cpp index 2feeb701c..153a870b7 100644 --- a/src/lib/marble/TourItemDelegate.cpp +++ b/src/lib/marble/TourItemDelegate.cpp @@ -1,546 +1,537 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2013 Mihail Ivchenko // Copyright 2014 Sanjiban Bairagya // Copyright 2014 Illya Kovalevskyy // #include #include #include #include #include #include #include "TourItemDelegate.h" #include "MarblePlacemarkModel.h" #include "geodata/data/GeoDataContainer.h" +#include "geodata/data/GeoDataFlyTo.h" #include "geodata/data/GeoDataObject.h" #include "geodata/data/GeoDataTourControl.h" #include "geodata/data/GeoDataWait.h" #include "geodata/data/GeoDataCoordinates.h" #include "geodata/data/GeoDataSoundCue.h" #include "geodata/data/GeoDataAnimatedUpdate.h" #include "FlyToEditWidget.h" #include "TourControlEditWidget.h" #include "SoundCueEditWidget.h" #include "WaitEditWidget.h" #include "RemoveItemEditWidget.h" #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" #include "GeoDataCreate.h" #include "GeoDataUpdate.h" #include "GeoDataDelete.h" #include "GeoDataChange.h" #include "EditPlacemarkDialog.h" #include "MarbleWidget.h" #include "GeoDataPlaylist.h" #include "TourWidget.h" namespace Marble { TourItemDelegate::TourItemDelegate( QListView* view, MarbleWidget* widget, TourWidget* tour ): m_listView( view ), m_widget( widget ), m_editable( true ), m_tourWidget( tour ) { QObject::connect( this, SIGNAL(editingChanged(QModelIndex)), m_listView, SLOT(update(QModelIndex)) ); m_listView->setEditTriggers( QAbstractItemView::NoEditTriggers ); } void TourItemDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { QStyleOptionViewItem styleOption = option; styleOption.text = QString(); QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &styleOption, painter); QAbstractTextDocumentLayout::PaintContext paintContext; if (styleOption.state & QStyle::State_Selected) { paintContext.palette.setColor(QPalette::Text, styleOption.palette.color(QPalette::Active, QPalette::HighlightedText)); } if ( m_listView->currentIndex() == index && m_tourWidget->isPlaying() ) { painter->fillRect( option.rect, paintContext.palette.color( QPalette::Midlight ) ); QStyledItemDelegate::paint( painter, option, index ); } QTextDocument label; QRect const labelRect = position(Label, option); label.setTextWidth( labelRect.width() ); label.setDefaultFont( option.font ); QStyleOptionButton button; button.state = option.state; button.palette = option.palette; button.features = QStyleOptionButton::None; button.iconSize = QSize( 16, 16 ); button.state &= ~QStyle::State_HasFocus; if( !editable() ) { button.state &= ~QStyle::State_Enabled; } QRect const iconRect = position( GeoDataElementIcon, option ); const GeoDataObject *object = qvariant_cast(index.data(MarblePlacemarkModel::ObjectPointerRole)); if (!m_editingIndices.contains(index)) { - if (object->nodeType() == GeoDataTypes::GeoDataTourControlType) { - const GeoDataTourControl *tourControl = static_cast(object); + if (const GeoDataTourControl *tourControl = geodata_cast(object)) { GeoDataTourControl::PlayMode const playMode = tourControl->playMode(); if ( playMode == GeoDataTourControl::Play ) { label.setHtml( tr("Play the tour") ); } else if ( playMode == GeoDataTourControl::Pause ) { label.setHtml( tr("Pause the tour") ); } painter->save(); painter->translate( labelRect.topLeft() ); painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() ); label.documentLayout()->draw( painter, paintContext ); painter->restore(); button.icon = QIcon(QStringLiteral(":/marble/document-edit.png")); QRect const buttonRect = position( EditButton, option );; button.rect = buttonRect; QIcon const icon = QIcon(QStringLiteral(":/marble/media-playback-pause.png")); painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) ); - } else if (object->nodeType() == GeoDataTypes::GeoDataFlyToType) { + } else if (geodata_cast(object)) { GeoDataCoordinates const flyToCoords = index.data( MarblePlacemarkModel::CoordinateRole ).value(); label.setHtml( flyToCoords.toString() ); button.icon = QIcon(QStringLiteral(":/marble/document-edit.png")); painter->save(); painter->translate( labelRect.topLeft() ); painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() ); label.documentLayout()->draw( painter, paintContext ); painter->restore(); QRect const buttonRect = position( EditButton, option ); button.rect = buttonRect; QIcon const icon = QIcon(QStringLiteral(":/marble/flag.png")); painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) ); - } else if (object->nodeType() == GeoDataTypes::GeoDataWaitType) { - const GeoDataWait *wait = static_cast(object); + } else if (const GeoDataWait *wait = geodata_cast(object)) { label.setHtml( tr("Wait for %1 seconds").arg( QString::number( wait->duration() ) ) ); painter->save(); painter->translate( labelRect.topLeft() ); painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() ); label.documentLayout()->draw( painter, paintContext ); painter->restore(); button.icon = QIcon(QStringLiteral(":/marble/document-edit.png")); QRect const buttonRect = position( EditButton, option ); button.rect = buttonRect; QIcon const icon = QIcon(QStringLiteral(":/marble/player-time.png")); painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) ); - } else if (object->nodeType() == GeoDataTypes::GeoDataSoundCueType) { - const GeoDataSoundCue *soundCue = static_cast(object); + } else if (const GeoDataSoundCue *soundCue = geodata_cast(object)) { label.setHtml(soundCue->href().section(QLatin1Char('/'), -1)); painter->save(); painter->translate( labelRect.topLeft() ); painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() ); label.documentLayout()->draw( painter, paintContext ); painter->restore(); QStyleOptionButton playButton = button; button.icon = QIcon(QStringLiteral(":/marble/document-edit.png")); QRect const buttonRect = position( EditButton, option ); button.rect = buttonRect; playButton.icon = QIcon(QStringLiteral(":/marble/playback-play.png")); QRect const playButtonRect = position( ActionButton, option ); playButton.rect = playButtonRect; QApplication::style()->drawControl( QStyle::CE_PushButton, &playButton, painter ); QIcon const icon = QIcon(QStringLiteral(":/marble/audio-x-generic.png")); painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) ); - } else if (object->nodeType() == GeoDataTypes::GeoDataAnimatedUpdateType) { - const GeoDataAnimatedUpdate *animUpdate = static_cast(object); + } else if (const GeoDataAnimatedUpdate *animUpdate = geodata_cast(object)) { const GeoDataUpdate *update = animUpdate->update(); bool ok = false; QString iconString; if( update && update->create() && update->create()->size() != 0 && (dynamic_cast(&update->create()->first()))) { const GeoDataContainer *container = static_cast(update->create()->child(0)); if( container->size() > 0 ) { label.setHtml( tr( "Create item %1" ).arg( container->first().id() ) ); ok = true; iconString = QStringLiteral(":/icons/add-placemark.png"); } } else if( update && update->getDelete() && update->getDelete()->size() != 0 ){ label.setHtml( tr( "Remove item %1" ).arg( update->getDelete()->first().targetId() ) ); ok = true; iconString = QStringLiteral(":/icons/remove.png"); } else if( update && update->change() && update->change()->size() != 0 ){ label.setHtml( tr( "Change item %1" ).arg( update->change()->first().targetId() ) ); ok = true; iconString = QStringLiteral(":/marble/document-edit.png"); } if( update && !ok ) { label.setHtml( tr( "Update items" ) ); button.state &= ~QStyle::State_Enabled & ~QStyle::State_Sunken; } painter->save(); painter->translate( labelRect.topLeft() ); painter->setClipRect( 0, 0, labelRect.width(), labelRect.height() ); label.documentLayout()->draw( painter, paintContext ); painter->restore(); button.icon = QIcon(QStringLiteral(":/marble/document-edit.png")); QRect const buttonRect = position( EditButton, option ); button.rect = buttonRect; QIcon const icon = QIcon( iconString ); painter->drawPixmap( iconRect, icon.pixmap( iconRect.size() ) ); } } QApplication::style()->drawControl( QStyle::CE_PushButton, &button, painter ); } QRect TourItemDelegate::position( Element element, const QStyleOptionViewItem &option ) { QPoint const topCol1 = option.rect.topLeft() + QPoint(10, 10); QPoint const topCol2 = topCol1 + QPoint(30, 0); QPoint const topCol3 = topCol2 + QPoint(210, 0); QPoint const topCol4 = topCol3 + QPoint(30, 0); QSize const labelSize = QSize(220, 30); QSize const iconsSize = QSize(22, 22); switch(element) { case GeoDataElementIcon: return QRect( topCol1, iconsSize ); case Label: return QRect( topCol2, labelSize ); case EditButton: return QRect( topCol3, iconsSize ); case ActionButton: return QRect( topCol4, iconsSize ); } return QRect(); } QStringList TourItemDelegate::findIds(const GeoDataPlaylist &playlist, bool onlyFeatures) { QStringList result; for (int i = 0; i < playlist.size(); ++i) { const GeoDataTourPrimitive *primitive = playlist.primitive(i); if( !primitive->id().isEmpty() && !onlyFeatures ) { result << primitive->id(); } - if( primitive->nodeType() == GeoDataTypes::GeoDataAnimatedUpdateType ) { - const GeoDataAnimatedUpdate *animatedUpdate = static_cast(primitive); + if (const GeoDataAnimatedUpdate *animatedUpdate = geodata_cast(primitive)) { if( animatedUpdate->update() != 0 ) { const GeoDataUpdate *update = animatedUpdate->update(); if( !update->id().isEmpty() && !onlyFeatures ) { result << update->id(); } if( update->create() != 0 ) { if( !update->create()->id().isEmpty() && !onlyFeatures ) { result << update->create()->id(); } for( int j = 0; j < update->create()->size(); ++j ) { if( !update->create()->at( j ).id().isEmpty() ) { result << update->create()->at( j ).id(); } } } if( update->change() != 0 ) { if( !update->change()->id().isEmpty() && !onlyFeatures ) { result << update->change()->id(); } for( int j = 0; j < update->change()->size(); ++j ) { if( !update->change()->at( j ).id().isEmpty() ) { result << update->change()->at( j ).id(); } } } if( update->getDelete() != 0 ) { if( !update->getDelete()->id().isEmpty() && !onlyFeatures ) { result << update->getDelete()->id(); } for( int j = 0; j < update->getDelete()->size(); ++j ) { if( !update->getDelete()->at( j ).id().isEmpty() ) { result << update->getDelete()->at( j ).id(); } } } } } } return result; } GeoDataPlaylist *TourItemDelegate::playlist() const { QModelIndex const rootIndex = m_listView->rootIndex(); if( rootIndex.isValid() ) { GeoDataObject *rootObject = static_cast( rootIndex.internalPointer() ); - if ( rootObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( rootObject ); + if (GeoDataPlaylist *playlist = geodata_cast(rootObject)) { return playlist; } } return 0; } QSize TourItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED( option ); Q_UNUSED( index ); return QSize(290,50); } QWidget* TourItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_UNUSED( option ); GeoDataObject *object = qvariant_cast(index.data( MarblePlacemarkModel::ObjectPointerRole ) ); - if ( object->nodeType() == GeoDataTypes::GeoDataFlyToType ) { + if (geodata_cast(object)) { FlyToEditWidget* widget = new FlyToEditWidget(index, m_widget, parent); widget->setFirstFlyTo( m_firstFlyTo ); connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex))); connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) ); connect( this, SIGNAL(firstFlyToChanged(QPersistentModelIndex)), widget, SLOT(setFirstFlyTo(QPersistentModelIndex)) ); return widget; - } else if ( object->nodeType() == GeoDataTypes::GeoDataTourControlType ) { + } else if (geodata_cast(object)) { TourControlEditWidget* widget = new TourControlEditWidget(index, parent); connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex))); connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) ); return widget; - } else if ( object->nodeType() == GeoDataTypes::GeoDataWaitType ) { + } else if (geodata_cast(object)) { WaitEditWidget* widget = new WaitEditWidget(index, parent); connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex))); connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) ); return widget; - } else if ( object->nodeType() == GeoDataTypes::GeoDataSoundCueType ) { + } else if (geodata_cast(object)) { SoundCueEditWidget* widget = new SoundCueEditWidget(index, parent); connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex))); connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) ); return widget; - } else if ( object->nodeType() == GeoDataTypes::GeoDataAnimatedUpdateType ) { + } else if (geodata_cast(object)) { RemoveItemEditWidget* widget = new RemoveItemEditWidget(index, parent); GeoDataPlaylist *playlistObject = playlist(); if( playlistObject != 0 ) { widget->setFeatureIds(findIds(*playlistObject)); } widget->setDefaultFeatureId( m_defaultFeatureId ); connect(widget, SIGNAL(editingDone(QModelIndex)), this, SLOT(closeEditor(QModelIndex))); connect( this, SIGNAL(editableChanged(bool)), widget, SLOT(setEditable(bool)) ); connect( this, SIGNAL(featureIdsChanged(QStringList)), widget, SLOT(setFeatureIds(QStringList)) ); connect( this, SIGNAL(defaultFeatureIdChanged(QString)), widget, SLOT(setDefaultFeatureId(QString)) ); return widget; } return 0; } bool TourItemDelegate::editable() const { return m_editable; } void TourItemDelegate::setEditable( bool editable ) { if( m_editable != editable ) { m_editable = editable; emit editableChanged( m_editable ); } } QModelIndex TourItemDelegate::firstFlyTo() const { return m_firstFlyTo; } bool TourItemDelegate::editAnimatedUpdate(GeoDataAnimatedUpdate *animatedUpdate, bool create) { if( animatedUpdate->update() == 0 ) { return false; } GeoDataFeature *feature = 0; if( create && !( animatedUpdate->update()->create() == 0 || animatedUpdate->update()->create()->size() == 0 ) ) { GeoDataContainer *container = dynamic_cast( animatedUpdate->update()->create()->child( 0 ) ); if( container != 0 && container->size() ) { feature = container->child( 0 ); } } else if ( !create && !( animatedUpdate->update()->change() == 0 || animatedUpdate->update()->change()->size() == 0 ) ) { GeoDataContainer *container = dynamic_cast( animatedUpdate->update()->change()->child( 0 ) ); if( container != 0 && container->size() ) { feature = container->child( 0 ); } } if( feature == 0 ) { return false; } QStringList ids; GeoDataPlacemark *placemark = static_cast( feature ); if( !create ) { if( placemark->targetId().isEmpty() && !defaultFeatureId().isEmpty() ) { GeoDataFeature *feature = findFeature( defaultFeatureId() ); - if( feature != 0 && feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *targetPlacemark = static_cast( feature ); + if (GeoDataPlacemark *targetPlacemark = (feature != 0 ? geodata_cast(feature) : 0)) { animatedUpdate->update()->change()->placemarkList().remove( 0 ); delete placemark; placemark = new GeoDataPlacemark( *targetPlacemark ); animatedUpdate->update()->change()->placemarkList().insert( 0, placemark ); placemark->setTargetId( defaultFeatureId() ); placemark->setId(QString()); } } } QPointer dialog = new EditPlacemarkDialog( placemark, nullptr, m_widget ); if( create ) { dialog->setWindowTitle( QObject::tr( "Add Placemark to Tour" ) ); } else { dialog->setWindowTitle( QObject::tr( "Change Placemark in Tour" ) ); dialog->setTargetIdFieldVisible( true ); dialog->setIdFieldVisible( false ); } GeoDataPlaylist* playlistObject = playlist(); if( playlistObject != 0 ) { ids.append(findIds(*playlistObject, true)); } ids.removeOne( placemark->id() ); if( create ) { dialog->setIdFilter( ids ); } else { dialog->setTargetIds( ids ); } bool status = dialog->exec(); if( !create ) { placemark->setId(QString()); } return status; } QString TourItemDelegate::defaultFeatureId() const { return m_defaultFeatureId; } GeoDataFeature *TourItemDelegate::findFeature(const QString &id) const { GeoDataPlaylist *playlistObject = playlist(); if( playlistObject == 0 ) { return 0; } GeoDataFeature *result = 0; for( int i = 0; i < playlistObject->size(); ++i ) { GeoDataTourPrimitive *primitive = playlistObject->primitive( i ); - if( primitive->nodeType() == GeoDataTypes::GeoDataAnimatedUpdateType ) { - GeoDataAnimatedUpdate *animatedUpdate = static_cast( primitive ); + if (GeoDataAnimatedUpdate *animatedUpdate = geodata_cast(primitive)) { if( animatedUpdate->update() != 0 ) { GeoDataUpdate *update = animatedUpdate->update(); if( update->create() != 0 ) { for( int j = 0; j < update->create()->featureList().size(); ++j ) { if( update->create()->at( j ).id() == id ) { result = update->create()->featureList().at( j ); } } } if( update->change() != 0 ) { for( int j = 0; j < update->change()->featureList().size(); ++j ) { if( update->change()->at( j ).id() == id ) { result = update->change()->featureList().at( j ); } } } if( update->getDelete() != 0 ) { for( int j = 0; j < update->getDelete()->featureList().size(); ++j ) { if( update->getDelete()->at( j ).id() == id ) { result = update->getDelete()->featureList().at( j ); } } } } } } return result; } void TourItemDelegate::setFirstFlyTo(const QPersistentModelIndex &index ) { m_firstFlyTo = index; emit firstFlyToChanged( m_firstFlyTo ); } void TourItemDelegate::setDefaultFeatureId(const QString &id) { m_defaultFeatureId = id; const QStringList ids = playlist() ? findIds(*playlist()) : QStringList(); emit featureIdsChanged( ids ); emit defaultFeatureIdChanged( id ); } bool TourItemDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index ) { Q_UNUSED( model ); if ( ( event->type() == QEvent::MouseButtonRelease ) && editable() ) { QMouseEvent *mouseEvent = static_cast( event ); QRect editRect = position( EditButton, option ); if ( editRect.contains( mouseEvent->pos() ) ) { if( m_editingIndices.contains( index ) ) { m_editingIndices.removeOne( index ); emit editingChanged( index ); return true; }else{ GeoDataObject *object = qvariant_cast(index.data( MarblePlacemarkModel::ObjectPointerRole ) ); - if( object->nodeType() == GeoDataTypes::GeoDataAnimatedUpdateType ) { - GeoDataAnimatedUpdate *animatedUpdate = static_cast( object ); + if (GeoDataAnimatedUpdate *animatedUpdate = geodata_cast(object)) { if( animatedUpdate->update() && animatedUpdate->update()->create() ) { if( editAnimatedUpdate( animatedUpdate ) ) { setDefaultFeatureId( m_defaultFeatureId ); } } else if( animatedUpdate->update() && animatedUpdate->update()->change() ) { editAnimatedUpdate( animatedUpdate, false ); } else if ( animatedUpdate->update() && animatedUpdate->update()->getDelete() ) { m_editingIndices.append( index ); m_listView->openPersistentEditor( index ); } } else { m_editingIndices.append( index ); m_listView->openPersistentEditor( index ); } } emit editingChanged( index ); return true; } } return false; } void TourItemDelegate::closeEditor( const QModelIndex &index ) { emit edited( index ); m_listView->closePersistentEditor( index ); m_editingIndices.removeOne( index ); } } #include "moc_TourItemDelegate.cpp" diff --git a/src/lib/marble/TourPlayback.cpp b/src/lib/marble/TourPlayback.cpp index f64aa8d09..94516d981 100644 --- a/src/lib/marble/TourPlayback.cpp +++ b/src/lib/marble/TourPlayback.cpp @@ -1,319 +1,311 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Sanjiban Bairagya // #include "TourPlayback.h" #include #include #include #include "MarbleDebug.h" #include "MarbleWidget.h" #include "PopupLayer.h" #include "GeoDataPoint.h" #include "GeoDataPlacemark.h" #include "GeoDataPlaylist.h" #include "GeoDataTour.h" #include "GeoDataWait.h" #include "GeoDataFlyTo.h" #include "GeoDataLookAt.h" #include "GeoDataTourControl.h" #include "GeoDataSoundCue.h" #include "GeoDataAnimatedUpdate.h" #include "MarbleModel.h" #include "GeoDataTreeModel.h" -#include "GeoDataTypes.h" #include "PlaybackFlyToItem.h" #include "PlaybackAnimatedUpdateItem.h" #include "PlaybackWaitItem.h" #include "PlaybackTourControlItem.h" #include "PlaybackSoundCueItem.h" #include "SerialTrack.h" #include "SoundTrack.h" #include "AnimatedUpdateTrack.h" namespace Marble { class TourPlaybackPrivate { public: TourPlaybackPrivate(); ~TourPlaybackPrivate(); GeoDataTour *m_tour; bool m_pause; SerialTrack m_mainTrack; QList m_soundTracks; QList m_animatedUpdateTracks; GeoDataFlyTo m_mapCenter; QPointer m_widget; QUrl m_baseUrl; }; TourPlaybackPrivate::TourPlaybackPrivate() : m_tour( 0 ), m_pause( false ), m_mainTrack(), m_widget( 0 ) { // do nothing } TourPlaybackPrivate::~TourPlaybackPrivate() { qDeleteAll(m_soundTracks); qDeleteAll(m_animatedUpdateTracks); } TourPlayback::TourPlayback(QObject *parent) : QObject(parent), d(new TourPlaybackPrivate()) { connect( &d->m_mainTrack, SIGNAL(centerOn(GeoDataCoordinates)), this, SLOT(centerOn(GeoDataCoordinates)) ); connect( &d->m_mainTrack, SIGNAL(progressChanged(double)), this, SIGNAL(progressChanged(double)) ); connect( &d->m_mainTrack, SIGNAL(finished()), this, SLOT(stopTour()) ); connect( &d->m_mainTrack, SIGNAL(itemFinished(int)), this, SLOT(handleFinishedItem(int)) ); } TourPlayback::~TourPlayback() { stop(); delete d; } void TourPlayback::handleFinishedItem( int index ) { emit itemFinished( index ); } void TourPlayback::stopTour() { for( SoundTrack* track: d->m_soundTracks ){ track->stop(); track->setPaused( false ); } for( int i = d->m_animatedUpdateTracks.size()-1; i >= 0; i-- ){ d->m_animatedUpdateTracks[ i ]->stop(); d->m_animatedUpdateTracks[ i ]->setPaused( false ); } emit finished(); } void TourPlayback::showBalloon( GeoDataPlacemark* placemark ) { GeoDataPoint* point = static_cast( placemark->geometry() ); d->m_widget->popupLayer()->setCoordinates( point->coordinates(), Qt::AlignRight | Qt::AlignVCenter ); d->m_widget->popupLayer()->setContent( placemark->description(), d->m_baseUrl ); d->m_widget->popupLayer()->setVisible( true ); d->m_widget->popupLayer()->setSize(QSizeF(500, 520)); } void TourPlayback::hideBalloon() { if( d->m_widget ){ d->m_widget->popupLayer()->setVisible( false ); } } bool TourPlayback::isPlaying() const { return !d->m_pause; } void TourPlayback::setMarbleWidget(MarbleWidget* widget) { d->m_widget = widget; connect( this, SIGNAL(added(GeoDataContainer*,GeoDataFeature*,int)), d->m_widget->model()->treeModel(), SLOT(addFeature(GeoDataContainer*,GeoDataFeature*,int)) ); connect( this, SIGNAL(removed(GeoDataFeature*)), d->m_widget->model()->treeModel(), SLOT(removeFeature(GeoDataFeature*)) ); connect( this, SIGNAL(updated(GeoDataFeature*)), d->m_widget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) ); } void TourPlayback::setBaseUrl( const QUrl &baseUrl ) { d->m_baseUrl = baseUrl; } QUrl TourPlayback::baseUrl() const { return d->m_baseUrl; } void TourPlayback::centerOn( const GeoDataCoordinates &coordinates ) { if ( d->m_widget ) { GeoDataLookAt lookat; lookat.setCoordinates( coordinates ); lookat.setRange( coordinates.altitude() ); d->m_widget->flyTo( lookat, Instant ); } } void TourPlayback::setTour(GeoDataTour *tour) { d->m_tour = tour; if ( !d->m_tour ) { clearTracks(); return; } updateTracks(); } void TourPlayback::play() { d->m_pause = false; GeoDataLookAt* lookat = new GeoDataLookAt( d->m_widget->lookAt() ); lookat->setAltitude( lookat->range() ); d->m_mapCenter.setView( lookat ); d->m_mainTrack.play(); for( SoundTrack* track: d->m_soundTracks) { track->play(); } for( AnimatedUpdateTrack* track: d->m_animatedUpdateTracks) { track->play(); } } void TourPlayback::pause() { d->m_pause = true; d->m_mainTrack.pause(); for( SoundTrack* track: d->m_soundTracks) { track->pause(); } for( AnimatedUpdateTrack* track: d->m_animatedUpdateTracks) { track->pause(); } } void TourPlayback::stop() { d->m_pause = true; d->m_mainTrack.stop(); for( SoundTrack* track: d->m_soundTracks) { track->stop(); } for( int i = d->m_animatedUpdateTracks.size()-1; i >= 0; i-- ){ d->m_animatedUpdateTracks[ i ]->stop(); } hideBalloon(); } void TourPlayback::seek( double value ) { double const offset = qBound( 0.0, value, d->m_mainTrack.duration() ); d->m_mainTrack.seek( offset ); for( SoundTrack* track: d->m_soundTracks ){ track->seek( offset ); } for( AnimatedUpdateTrack* track: d->m_animatedUpdateTracks ){ track->seek( offset ); } } int TourPlayback::mainTrackSize() { return d->m_mainTrack.size(); } PlaybackItem* TourPlayback::mainTrackItemAt( int i ) { return d->m_mainTrack.at( i ); } void TourPlayback::updateTracks() { clearTracks(); double delay = 0; for( int i = 0; i < d->m_tour->playlist()->size(); i++){ GeoDataTourPrimitive* primitive = d->m_tour->playlist()->primitive( i ); - if( primitive->nodeType() == GeoDataTypes::GeoDataFlyToType ){ - const GeoDataFlyTo *flyTo = dynamic_cast(primitive); + if (const auto flyTo = geodata_cast(primitive)){ d->m_mainTrack.append( new PlaybackFlyToItem( flyTo ) ); delay += flyTo->duration(); } - else if( primitive->nodeType() == GeoDataTypes::GeoDataWaitType ){ - const GeoDataWait *wait = dynamic_cast(primitive); - + else if (const auto wait = geodata_cast(primitive)) { d->m_mainTrack.append( new PlaybackWaitItem( wait ) ); delay += wait->duration(); } - else if( primitive->nodeType() == GeoDataTypes::GeoDataTourControlType ){ - const GeoDataTourControl *tourControl = dynamic_cast(primitive); - + else if (const auto tourControl = geodata_cast(primitive)) { d->m_mainTrack.append( new PlaybackTourControlItem( tourControl ) ); } - else if( primitive->nodeType() == GeoDataTypes::GeoDataSoundCueType ){ - const GeoDataSoundCue *soundCue = dynamic_cast(primitive); + else if (const auto soundCue = geodata_cast(primitive)) { PlaybackSoundCueItem *item = new PlaybackSoundCueItem( soundCue ); SoundTrack *track = new SoundTrack( item ); track->setDelayBeforeTrackStarts( delay ); d->m_soundTracks.append( track ); } - else if( primitive->nodeType() == GeoDataTypes::GeoDataAnimatedUpdateType ){ - GeoDataAnimatedUpdate *animatedUpdate = dynamic_cast(primitive); + else if (const auto animatedUpdate = geodata_cast(primitive)) { PlaybackAnimatedUpdateItem *item = new PlaybackAnimatedUpdateItem( animatedUpdate ); AnimatedUpdateTrack *track = new AnimatedUpdateTrack( item ); track->setDelayBeforeTrackStarts( delay + animatedUpdate->delayedStart() ); d->m_animatedUpdateTracks.append( track ); connect( track, SIGNAL(balloonHidden()), this, SLOT(hideBalloon()) ); connect( track, SIGNAL(balloonShown(GeoDataPlacemark*)), this, SLOT(showBalloon(GeoDataPlacemark*)) ); connect( track, SIGNAL(updated(GeoDataFeature*)), this, SIGNAL(updated(GeoDataFeature*)) ); connect( track, SIGNAL(added(GeoDataContainer*,GeoDataFeature*,int)), this, SIGNAL(added(GeoDataContainer*,GeoDataFeature*,int)) ); connect( track, SIGNAL(removed(const GeoDataFeature*)), this, SIGNAL(removed(const GeoDataFeature*)) ); } } Q_ASSERT( d->m_widget ); GeoDataLookAt* lookat = new GeoDataLookAt( d->m_widget->lookAt() ); lookat->setAltitude( lookat->range() ); d->m_mapCenter.setView( lookat ); PlaybackFlyToItem* mapCenterItem = new PlaybackFlyToItem( &d->m_mapCenter ); PlaybackFlyToItem* before = mapCenterItem; for ( int i=0; im_mainTrack.size(); ++i ) { PlaybackFlyToItem* item = qobject_cast( d->m_mainTrack.at(i) ); if ( item ) { item->setBefore( before ); before = item; } } PlaybackFlyToItem* next = 0; for ( int i=d->m_mainTrack.size()-1; i>=0; --i ) { PlaybackFlyToItem* item = qobject_cast( d->m_mainTrack.at(i) ); if ( item ) { item->setNext( next ); next = item; } } } void TourPlayback::clearTracks() { d->m_mainTrack.clear(); qDeleteAll(d->m_soundTracks); qDeleteAll(d->m_animatedUpdateTracks); d->m_soundTracks.clear(); d->m_animatedUpdateTracks.clear(); } double TourPlayback::duration() const { return d->m_mainTrack.duration(); } } // namespace Marble #include "moc_TourPlayback.cpp" diff --git a/src/lib/marble/TourWidget.cpp b/src/lib/marble/TourWidget.cpp index 6e82b4ff2..8bbf2e9b7 100644 --- a/src/lib/marble/TourWidget.cpp +++ b/src/lib/marble/TourWidget.cpp @@ -1,982 +1,972 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2013 Mihail Ivchenko // Copyright 2014 Sanjiban Bairagya // #include "TourWidget.h" #include "FlyToEditWidget.h" #include "TourControlEditWidget.h" #include "WaitEditWidget.h" #include "SoundCueEditWidget.h" #include "TourItemDelegate.h" #include "ui_TourWidget.h" #include "GeoDataPlacemark.h" #include "GeoDataDocument.h" #include "GeoDataLookAt.h" #include "GeoDataPlaylist.h" #include "GeoDataTour.h" #include "GeoDataTreeModel.h" -#include "GeoDataTypes.h" #include "GeoDataFlyTo.h" #include "GeoDataWait.h" #include "GeoDataCamera.h" #include "GeoDataTourControl.h" #include "GeoDataSoundCue.h" #include "GeoDataCreate.h" #include "GeoDataUpdate.h" #include "GeoDataDelete.h" #include "GeoDataChange.h" #include "GeoDataAnimatedUpdate.h" #include "GeoDataDocumentWriter.h" #include "KmlElementDictionary.h" #include "MarbleModel.h" #include "MarblePlacemarkModel.h" #include "MarbleWidget.h" #include "ParsingRunnerManager.h" #include "TourPlayback.h" #include "MovieCapture.h" #include "TourCaptureDialog.h" #include "MarbleDebug.h" #include "PlaybackFlyToItem.h" #include "EditPlacemarkDialog.h" #include "MarbleDirs.h" #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include #include #include #include #include #include #include #include #include #include #include namespace Marble { class TourWidgetPrivate { public: explicit TourWidgetPrivate( TourWidget *parent ); ~TourWidgetPrivate(); GeoDataFeature *getPlaylistFeature() const; void updateRootIndex(); public: void openFile(); bool openFile( const QString &filename ); void createTour(); void saveTour(); void saveTourAs(); void mapCenterOn(const QModelIndex &index ); void addFlyTo(); void addWait(); void addSoundCue(); void addPlacemark(); void addRemovePlacemark(); void addChangePlacemark(); void addTourPrimitive(GeoDataTourPrimitive *primitive ); void deleteSelected(); void updateButtonsStates(); void moveUp(); void moveDown(); void captureTour(); void handlePlaybackProgress( const double position ); void handlePlaybackFinish(); GeoDataObject *rootIndexObject() const; private: GeoDataTour* findTour( GeoDataFeature* feature ) const; bool openDocument( GeoDataDocument *document ); bool saveTourAs( const QString &filename ); bool overrideModifications(); public: TourWidget *q; MarbleWidget *m_widget; Ui::TourWidget m_tourUi; TourCaptureDialog *m_tourCaptureDialog; TourPlayback m_playback; TourItemDelegate *m_delegate; bool m_isChanged; bool m_playState; bool m_isLoopingStopped; GeoDataDocument* m_document; QAction *m_actionToggleLoopPlay; QToolButton *m_addPrimitiveButton; QAction *m_actionAddFlyTo; QAction *m_actionAddWait; QAction *m_actionAddSoundCue; QAction *m_actionAddPlacemark; QAction *m_actionAddRemovePlacemark; QAction *m_actionAddChangePlacemark; }; TourWidgetPrivate::TourWidgetPrivate( TourWidget *parent ) : q( parent ), m_widget( 0 ), m_playback( 0 ), m_delegate( 0 ), m_isChanged( false ), m_playState( false ), m_document( 0 ), m_addPrimitiveButton( new QToolButton ) { m_tourUi.setupUi( parent ); m_tourUi.m_actionRecord->setEnabled( false ); QAction *separator = m_tourUi.m_toolBarControl->insertSeparator( m_tourUi.m_actionMoveUp ); m_addPrimitiveButton->setIcon(QIcon(QStringLiteral(":/marble/flag.png"))); m_addPrimitiveButton->setToolTip( QObject::tr( "Add FlyTo" ) ); m_addPrimitiveButton->setPopupMode( QToolButton::MenuButtonPopup ); QMenu *addPrimitiveMenu = new QMenu(q); m_actionAddFlyTo = new QAction(QIcon(QStringLiteral(":/marble/flag.png")), QObject::tr("Add FlyTo"), addPrimitiveMenu); addPrimitiveMenu->addAction( m_actionAddFlyTo ); m_actionAddWait = new QAction(QIcon(QStringLiteral(":/marble/player-time.png")), QObject::tr("Add Wait"), addPrimitiveMenu); addPrimitiveMenu->addAction( m_actionAddWait ); m_actionAddSoundCue = new QAction(QIcon(QStringLiteral(":/marble/audio-x-generic.png")), QObject::tr("Add SoundCue"), addPrimitiveMenu); addPrimitiveMenu->addAction( m_actionAddSoundCue ); addPrimitiveMenu->addSeparator(); m_actionAddPlacemark = new QAction(QIcon(QStringLiteral(":/icons/add-placemark.png")), QObject::tr("Add Placemark"), addPrimitiveMenu); addPrimitiveMenu->addAction( m_actionAddPlacemark ); m_actionAddRemovePlacemark = new QAction(QIcon(QStringLiteral(":/icons/remove.png")), QObject::tr("Remove placemark"), addPrimitiveMenu); addPrimitiveMenu->addAction( m_actionAddRemovePlacemark ); m_actionAddChangePlacemark = new QAction(QIcon(QStringLiteral(":/marble/document-edit.png")), QObject::tr("Change placemark"), addPrimitiveMenu); addPrimitiveMenu->addAction( m_actionAddChangePlacemark ); m_actionToggleLoopPlay = new QAction( QObject::tr( "Loop" ), m_tourUi.m_slider ); m_actionToggleLoopPlay->setCheckable( true ); m_actionToggleLoopPlay->setChecked( false ); m_tourUi.m_slider->setContextMenuPolicy( Qt::ActionsContextMenu ); m_tourUi.m_slider->addAction( m_actionToggleLoopPlay ); m_addPrimitiveButton->setMenu( addPrimitiveMenu ); m_addPrimitiveButton->setEnabled( false ); m_tourUi.m_toolBarControl->insertWidget( separator, m_addPrimitiveButton ); QObject::connect( m_tourUi.m_listView, SIGNAL(activated(QModelIndex)), q, SLOT(mapCenterOn(QModelIndex)) ); QObject::connect( m_addPrimitiveButton, SIGNAL(clicked()), q, SLOT(addFlyTo()) ); QObject::connect( m_actionAddFlyTo, SIGNAL(triggered()), q, SLOT(addFlyTo()) ); QObject::connect( m_actionAddWait, SIGNAL(triggered()), q, SLOT(addWait()) ); QObject::connect( m_actionAddSoundCue, SIGNAL(triggered()), q, SLOT(addSoundCue()) ); QObject::connect( m_actionAddPlacemark, SIGNAL(triggered()), q, SLOT(addPlacemark()) ); QObject::connect( m_actionAddRemovePlacemark, SIGNAL(triggered()), q, SLOT(addRemovePlacemark()) ); QObject::connect( m_actionAddChangePlacemark, SIGNAL(triggered()), q, SLOT(addChangePlacemark()) ); QObject::connect( m_tourUi.m_actionDelete, SIGNAL(triggered()), q, SLOT(deleteSelected()) ); QObject::connect( m_tourUi.m_actionMoveUp, SIGNAL(triggered()), q, SLOT(moveUp()) ); QObject::connect( m_tourUi.m_actionMoveDown, SIGNAL(triggered()), q, SLOT(moveDown()) ); QObject::connect( m_tourUi.m_actionNewTour, SIGNAL(triggered()), q, SLOT(createTour()) ); QObject::connect( m_tourUi.m_actionOpenTour, SIGNAL(triggered()), q, SLOT(openFile()) ); QObject::connect( m_tourUi.m_actionSaveTour, SIGNAL(triggered()), q, SLOT(saveTour()) ); QObject::connect( m_tourUi.m_actionSaveTourAs, SIGNAL(triggered()), q, SLOT(saveTourAs()) ); QObject::connect( m_tourUi.m_actionRecord, SIGNAL(triggered()), q, SLOT(captureTour()) ); QObject::connect( &m_playback, SIGNAL(finished()), q, SLOT(stopPlaying()) ); QObject::connect( &m_playback, SIGNAL(itemFinished(int)), q, SLOT(setHighlightedItemIndex(int)) ); } TourWidgetPrivate::~TourWidgetPrivate() { delete m_delegate; } TourWidget::TourWidget( QWidget *parent, Qt::WindowFlags flags ) : QWidget( parent, flags ), d( new TourWidgetPrivate( this ) ) { layout()->setMargin( 0 ); connect( d->m_tourUi.actionPlay, SIGNAL(triggered()), this, SLOT(togglePlaying()) ); connect( d->m_tourUi.actionStop, SIGNAL(triggered()), this, SLOT(stopLooping()) ); connect( d->m_tourUi.actionStop, SIGNAL(triggered()), this, SLOT(stopPlaying()) ); connect( d->m_tourUi.m_slider, SIGNAL(sliderMoved(int)), this, SLOT(handleSliderMove(int)) ); d->m_tourUi.m_toolBarPlayback->setDisabled( true ); d->m_tourUi.m_slider->setDisabled( true ); d->m_tourUi.m_listView->installEventFilter( this ); } TourWidget::~TourWidget() { delete d; } bool TourWidget::eventFilter( QObject *watched, QEvent *event ) { Q_UNUSED(watched); Q_ASSERT( watched == d->m_tourUi.m_listView ); GeoDataObject *rootObject = d->rootIndexObject(); if ( !rootObject ) { return false; } if ( event->type() == QEvent::KeyPress ) { QKeyEvent *key = static_cast( event ); QModelIndexList selectedIndexes = d->m_tourUi.m_listView->selectionModel()->selectedIndexes(); if ( key->key() == Qt::Key_Delete ) { if ( !selectedIndexes.isEmpty() ) { deleteSelected(); } return true; } if ( key->key() == Qt::Key_PageDown && key->modifiers().testFlag( Qt::ControlModifier ) && !selectedIndexes.isEmpty() ) { QModelIndexList::iterator end = selectedIndexes.end() - 1; - if ( rootObject && rootObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( rootObject ); - + if (const GeoDataPlaylist *playlist = (rootObject ? geodata_cast(rootObject) : 0)) { if ( end->row() != playlist->size() - 1 ) { moveDown(); } } return true; } if ( key->key() == Qt::Key_PageUp && key->modifiers().testFlag( Qt::ControlModifier ) && !selectedIndexes.isEmpty() ) { QModelIndexList::iterator start = selectedIndexes.begin(); if ( start->row() != 0 ) { moveUp(); } return true; } } return false; } void TourWidget::setMarbleWidget( MarbleWidget *widget ) { d->m_widget = widget; delete d->m_delegate; d->m_delegate = new TourItemDelegate( d->m_tourUi.m_listView, d->m_widget, this ); connect( d->m_delegate, SIGNAL(edited(QModelIndex)), this, SLOT(updateDuration()) ); connect( d->m_delegate, SIGNAL(edited(QModelIndex)), &d->m_playback, SLOT(updateTracks()) ); d->m_tourUi.m_listView->setItemDelegate( d->m_delegate ); } void TourWidget::togglePlaying() { if( !d->m_playState ){ d->m_playState = true; startPlaying(); } else { d->m_playState = false; pausePlaying(); } } void TourWidget::startPlaying() { setHighlightedItemIndex( 0 ); d->m_isLoopingStopped = false; d->m_playback.play(); d->m_tourUi.actionPlay->setIcon(QIcon(QStringLiteral(":/marble/playback-pause.png"))); d->m_tourUi.actionPlay->setEnabled( true ); d->m_tourUi.actionStop->setEnabled( true ); d->m_tourUi.m_actionRecord->setEnabled( false ); d->m_delegate->setEditable( false ); d->m_addPrimitiveButton->setEnabled( false ); d->m_playState = true; } void TourWidget::pausePlaying() { d->m_playback.pause(); d->m_tourUi.actionPlay->setIcon(QIcon(QStringLiteral(":/marble/playback-play.png"))); d->m_tourUi.actionPlay->setEnabled( true ); d->m_tourUi.actionStop->setEnabled( true ); } void TourWidget::stopPlaying() { removeHighlight(); d->m_playback.stop(); d->m_tourUi.actionPlay->setIcon(QIcon(QStringLiteral(":/marble/playback-play.png"))); d->m_tourUi.actionPlay->setEnabled( true ); d->m_tourUi.m_actionRecord->setEnabled( true ); d->m_tourUi.actionStop->setEnabled( false ); d->m_playState = false; d->m_delegate->setEditable( true ); d->m_addPrimitiveButton->setEnabled( true ); // Loop if the option ( m_actionLoopPlay ) is checked if ( d->m_actionToggleLoopPlay->isChecked() && !d->m_isLoopingStopped ) { startPlaying(); } } void TourWidget::stopLooping() { d->m_isLoopingStopped = true; } void TourWidget::closeEvent( QCloseEvent *event ) { if ( !d->m_document || !d->m_isChanged ) { event->accept(); return; } const int result = QMessageBox::question( d->m_widget, QObject::tr( "Save tour" ), QObject::tr( "There are unsaved Tours. Do you want to save your changes?" ), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel ); switch ( result ) { case QMessageBox::Save: d->saveTour(); event->accept(); break; case QMessageBox::Discard: event->accept(); break; case QMessageBox::Cancel: event->ignore(); } } void TourWidget::handleSliderMove( int value ) { removeHighlight(); d->m_playback.seek( value / 100.0 ); QTime nullTime( 0, 0, 0 ); QTime time = nullTime.addSecs( value / 100.0 ); d->m_tourUi.m_elapsedTime->setText(QString("%L1:%L2").arg(time.minute(), 2, 10, QLatin1Char('0')).arg(time.second(), 2, 10, QLatin1Char('0'))); } void TourWidgetPrivate::openFile() { if ( overrideModifications() ) { QString const filename = QFileDialog::getOpenFileName( q, QObject::tr( "Open Tour" ), QDir::homePath(), QObject::tr( "KML Tours (*.kml)" ) ); if ( !filename.isEmpty() ) { ParsingRunnerManager manager( m_widget->model()->pluginManager() ); GeoDataDocument* document = manager.openFile( filename ); m_playback.setBaseUrl( QUrl::fromLocalFile( filename ) ); openDocument( document ); } } } bool TourWidgetPrivate::openFile( const QString &filename ) { if ( overrideModifications() ) { if ( !filename.isEmpty() ) { ParsingRunnerManager manager( m_widget->model()->pluginManager() ); GeoDataDocument* document = manager.openFile( filename ); m_playback.setBaseUrl( QUrl::fromLocalFile( filename ) ); return openDocument( document ); } } return false; } GeoDataTour *TourWidgetPrivate::findTour( GeoDataFeature *feature ) const { - if ( feature && feature->nodeType() == GeoDataTypes::GeoDataTourType ) { - return static_cast( feature ); + if (GeoDataTour *tour = (feature ? geodata_cast(feature) : 0)) { + return tour; } GeoDataContainer *container = dynamic_cast( feature ); if ( container ) { QVector::Iterator end = container->end(); QVector::Iterator iter = container->begin(); for( ; iter != end; ++iter ) { GeoDataTour *tour = findTour( *iter ); if ( tour ) { return tour; } } } return 0; } void TourWidgetPrivate::mapCenterOn( const QModelIndex &index ) { QVariant coordinatesVariant = m_widget->model()->treeModel()->data( index, MarblePlacemarkModel::CoordinateRole ); if ( !coordinatesVariant.isNull() ) { GeoDataCoordinates const coordinates = coordinatesVariant.value(); GeoDataLookAt lookat; lookat.setCoordinates( coordinates ); lookat.setRange( coordinates.altitude() ); m_widget->flyTo( lookat, Instant ); } } void TourWidgetPrivate::addFlyTo() { GeoDataFlyTo *flyTo = new GeoDataFlyTo(); GeoDataLookAt *lookat = new GeoDataLookAt( m_widget->lookAt() ); lookat->setAltitude( lookat->range() ); flyTo->setView( lookat ); bool isMainTrackEmpty = m_playback.mainTrackSize() == 0; flyTo->setDuration( isMainTrackEmpty ? 0.0 : 1.0 ); addTourPrimitive( flyTo ); } void TourWidgetPrivate::addWait() { GeoDataWait *wait = new GeoDataWait(); wait->setDuration( 1.0 ); addTourPrimitive( wait ); } void TourWidgetPrivate::addSoundCue() { GeoDataSoundCue *soundCue = new GeoDataSoundCue(); addTourPrimitive( soundCue ); } void TourWidgetPrivate::addPlacemark() { // Get the normalized coordinates of the focus point. There will be automatically added a new // placemark. qreal lat = m_widget->focusPoint().latitude(); qreal lon = m_widget->focusPoint().longitude(); GeoDataCoordinates::normalizeLonLat( lon, lat ); GeoDataDocument *document = new GeoDataDocument; if( m_document->id().isEmpty() ) { if( m_document->name().isEmpty() ) { m_document->setId(QStringLiteral("untitled_tour")); } else { m_document->setId( m_document->name().trimmed().replace( QLatin1Char(' '), QLatin1Char('_') ).toLower() ); } } document->setTargetId( m_document->id() ); GeoDataPlacemark *placemark = new GeoDataPlacemark; placemark->setCoordinate( lon, lat ); placemark->setVisible( true ); placemark->setBalloonVisible( true ); GeoDataStyle *newStyle = new GeoDataStyle( *placemark->style() ); newStyle->iconStyle().setIconPath(MarbleDirs::path(QStringLiteral("bitmaps/redflag_22.png"))); placemark->setStyle( GeoDataStyle::Ptr(newStyle) ); document->append( placemark ); GeoDataCreate *create = new GeoDataCreate; create->append( document ); GeoDataUpdate *update = new GeoDataUpdate; update->setCreate( create ); GeoDataAnimatedUpdate *animatedUpdate = new GeoDataAnimatedUpdate; animatedUpdate->setUpdate( update ); if( m_delegate->editAnimatedUpdate( animatedUpdate ) ) { addTourPrimitive( animatedUpdate ); m_delegate->setDefaultFeatureId( placemark->id() ); } else { delete animatedUpdate; } } void TourWidgetPrivate::addRemovePlacemark() { GeoDataDelete *deleteItem = new GeoDataDelete; GeoDataPlacemark *placemark = new GeoDataPlacemark; placemark->setTargetId( m_delegate->defaultFeatureId() ); deleteItem->append( placemark ); GeoDataUpdate *update = new GeoDataUpdate; update->setDelete( deleteItem ); GeoDataAnimatedUpdate *animatedUpdate = new GeoDataAnimatedUpdate; animatedUpdate->setUpdate( update ); addTourPrimitive( animatedUpdate ); } void TourWidgetPrivate::addChangePlacemark() { GeoDataChange *change = new GeoDataChange; GeoDataPlacemark *placemark = 0; GeoDataFeature *lastFeature = m_delegate->findFeature( m_delegate->defaultFeatureId() ); - if( lastFeature != 0 && lastFeature->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *target = static_cast( lastFeature ); + if (GeoDataPlacemark *target = (lastFeature != 0 ? geodata_cast(lastFeature) : 0)) { placemark = new GeoDataPlacemark( *target ); placemark->setTargetId( m_delegate->defaultFeatureId() ); placemark->setId(QString()); } else { placemark = new GeoDataPlacemark; } change->append( placemark ); GeoDataUpdate *update = new GeoDataUpdate; update->setChange( change ); GeoDataAnimatedUpdate *animatedUpdate = new GeoDataAnimatedUpdate; animatedUpdate->setUpdate( update ); addTourPrimitive( animatedUpdate ); } void TourWidgetPrivate::addTourPrimitive( GeoDataTourPrimitive *primitive ) { GeoDataObject *rootObject = rootIndexObject(); - if ( rootObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( rootObject ); + if (auto playlist = geodata_cast(rootObject)) { QModelIndex currentIndex = m_tourUi.m_listView->currentIndex(); QModelIndex playlistIndex = m_widget->model()->treeModel()->index( playlist ); int row = currentIndex.isValid() ? currentIndex.row()+1 : playlist->size(); m_widget->model()->treeModel()->addTourPrimitive( playlistIndex, primitive, row ); m_isChanged = true; m_tourUi.m_actionSaveTour->setEnabled( true ); // Scrolling to the inserted item. if ( currentIndex.isValid() ) { m_tourUi.m_listView->scrollTo( currentIndex ); } else { m_tourUi.m_listView->scrollToBottom(); } } } void TourWidgetPrivate::deleteSelected() { QString title = QObject::tr( "Remove Selected Items" ); QString text = QObject::tr( "Are you sure want to remove selected items?" ); QPointer dialog = new QMessageBox( QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::No, q ); dialog->setDefaultButton( QMessageBox::No ); if ( dialog->exec() == QMessageBox::Yes ) { GeoDataObject *rootObject = rootIndexObject(); - if ( rootObject && rootObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( rootObject ); + if (GeoDataPlaylist *playlist = (rootObject ? geodata_cast(rootObject) : 0)) { QModelIndex playlistIndex = m_widget->model()->treeModel()->index( playlist ); QModelIndexList selected = m_tourUi.m_listView->selectionModel()->selectedIndexes(); std::sort( selected.begin(), selected.end(), [](const QModelIndex &a, const QModelIndex &b) { return b < a; } ); QModelIndexList::iterator end = selected.end(); QModelIndexList::iterator iter = selected.begin(); for( ; iter != end; ++iter ) { m_widget->model()->treeModel()->removeTourPrimitive( playlistIndex, iter->row() ); } m_isChanged = true; m_tourUi.m_actionSaveTour->setEnabled( true ); } } delete dialog; } void TourWidgetPrivate::updateButtonsStates() { QModelIndexList selectedIndexes = m_tourUi.m_listView->selectionModel()->selectedIndexes(); if ( selectedIndexes.isEmpty() ) { m_tourUi.m_actionDelete->setEnabled( false ); m_tourUi.m_actionMoveDown->setEnabled( false ); m_tourUi.m_actionMoveUp->setEnabled( false ); } else { m_tourUi.m_actionDelete->setEnabled( true ); std::sort( selectedIndexes.begin(), selectedIndexes.end(), std::less() ); QModelIndexList::iterator end = selectedIndexes.end()-1; QModelIndexList::iterator start = selectedIndexes.begin(); m_tourUi.m_actionMoveUp->setEnabled( ( start->row() != 0 ) ); // if we can move up enable action else disable. GeoDataObject *rootObject = rootIndexObject(); - if ( rootObject && rootObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( rootObject ); + if (GeoDataPlaylist *playlist = (rootObject ? geodata_cast(rootObject) : 0)) { m_tourUi.m_actionMoveDown->setEnabled( ( end->row() != playlist->size()-1 ) ); // if we can move down enable action else disable. } } } void TourWidgetPrivate::moveUp() { GeoDataObject *rootObject = rootIndexObject(); - if ( rootObject && rootObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( rootObject ); + if (GeoDataPlaylist *playlist = (rootObject ? geodata_cast(rootObject) : 0)) { QModelIndex playlistIndex = m_widget->model()->treeModel()->index( playlist ); QModelIndexList selected = m_tourUi.m_listView->selectionModel()->selectedIndexes(); std::sort( selected.begin(), selected.end(), std::less() ); QModelIndexList::iterator end = selected.end(); QModelIndexList::iterator iter = selected.begin(); for( ; iter != end; ++iter ) { int const index = iter->row(); Q_ASSERT( index > 0 ); m_widget->model()->treeModel()->swapTourPrimitives( playlistIndex, index-1, index ); } m_isChanged = true; m_tourUi.m_actionSaveTour->setEnabled( true ); updateButtonsStates(); } } void TourWidgetPrivate::moveDown() { GeoDataObject *rootObject = rootIndexObject(); - if ( rootObject && rootObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( rootObject ); + if (GeoDataPlaylist *playlist = (rootObject ? geodata_cast(rootObject) : 0)) { QModelIndex playlistIndex = m_widget->model()->treeModel()->index( playlist ); QModelIndexList selected = m_tourUi.m_listView->selectionModel()->selectedIndexes(); std::sort( selected.begin(), selected.end(), [](const QModelIndex &a, const QModelIndex &b) { return b < a; } ); QModelIndexList::iterator end = selected.end(); QModelIndexList::iterator iter = selected.begin(); for( ; iter != end; ++iter ) { int const index = iter->row(); Q_ASSERT( index < playlist->size()-1 ); m_widget->model()->treeModel()->swapTourPrimitives( playlistIndex, index, index+1 ); } m_isChanged = true; m_tourUi.m_actionSaveTour->setEnabled( true ); updateButtonsStates(); } } GeoDataFeature* TourWidgetPrivate::getPlaylistFeature() const { GeoDataObject *rootObject = rootIndexObject(); - if ( rootObject && rootObject->nodeType() == GeoDataTypes::GeoDataPlaylistType ) { - GeoDataPlaylist *playlist = static_cast( rootObject ); + if (GeoDataPlaylist *playlist = (rootObject ? geodata_cast(rootObject) : 0)) { GeoDataObject *object = playlist->parent(); - if ( object && object->nodeType() == GeoDataTypes::GeoDataTourType ) { - return static_cast( object ); + if (GeoDataTour *tour = (object ? geodata_cast(object) : 0)) { + return tour; } } return 0; } void TourWidgetPrivate::updateRootIndex() { GeoDataTour *tour = findTour( m_document ); if ( tour ){ GeoDataPlaylist *playlist = tour->playlist(); if ( playlist ) { m_tourUi.m_listView->setModel( m_widget->model()->treeModel() ); m_tourUi.m_listView->setRootIndex( m_widget->model()->treeModel()->index( playlist ) ); QObject::connect( m_tourUi.m_listView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(updateButtonsStates()) ); } m_playback.setMarbleWidget( m_widget ); m_playback.setTour( tour ); m_tourUi.m_slider->setMaximum( m_playback.duration() * 100 ); QTime nullTime( 0, 0, 0 ); QTime time = nullTime.addSecs( m_playback.duration() ); m_tourUi.m_totalTime->setText(QString("%L1:%L2").arg(time.minute(), 2, 10, QLatin1Char('0')).arg(time.second(), 2, 10, QLatin1Char('0'))); QObject::connect( &m_playback, SIGNAL(progressChanged(double)), q, SLOT(handlePlaybackProgress(double)) ); q->stopPlaying(); m_tourUi.m_toolBarPlayback->setEnabled( true ); bool isPlaybackEmpty = m_playback.mainTrackSize() != 0; m_tourUi.actionPlay->setEnabled( isPlaybackEmpty ); m_tourUi.m_slider->setEnabled( isPlaybackEmpty ); m_tourUi.m_actionRecord->setEnabled( isPlaybackEmpty ); m_tourUi.actionStop->setEnabled( false ); if( m_playback.mainTrackSize() > 0 ) { if( dynamic_cast( m_playback.mainTrackItemAt( 0 ) ) ) { QModelIndex playlistIndex = m_widget->model()->treeModel()->index( playlist ); for( int i = 0; playlist && i < playlist->size(); ++i ) { - if( playlist->primitive( i )->nodeType() == GeoDataTypes::GeoDataFlyToType ) { + if (geodata_cast(playlist->primitive(i))) { m_delegate->setFirstFlyTo( m_widget->model()->treeModel()->index( i, 0, playlistIndex ) ); break; } } } else { m_delegate->setFirstFlyTo( QPersistentModelIndex() ); } } } } void TourWidget::addFlyTo() { d->addFlyTo(); finishAddingItem(); } void TourWidget::addWait() { d->addWait(); finishAddingItem(); } void TourWidget::addSoundCue() { d->addSoundCue(); finishAddingItem(); } void TourWidget::addPlacemark() { d->addPlacemark(); finishAddingItem(); } void TourWidget::addRemovePlacemark() { d->addRemovePlacemark(); finishAddingItem(); } void TourWidget::addChangePlacemark() { d->addChangePlacemark(); finishAddingItem(); } void TourWidget::deleteSelected() { d->deleteSelected(); GeoDataFeature *feature = d->getPlaylistFeature(); if ( feature ) { emit featureUpdated( feature ); d->updateRootIndex(); } } void TourWidget::updateDuration() { d->m_tourUi.m_slider->setMaximum( d->m_playback.duration() * 100 ); QTime nullTime( 0, 0, 0 ); QTime totalTime = nullTime.addSecs( d->m_playback.duration() ); d->m_tourUi.m_totalTime->setText(QString("%L1:%L2").arg(totalTime.minute(), 2, 10, QLatin1Char('0') ).arg(totalTime.second(), 2, 10, QLatin1Char('0'))); d->m_tourUi.m_slider->setValue( 0 ); d->m_tourUi.m_elapsedTime->setText(QString("%L1:%L2").arg(0, 2, 10, QLatin1Char('0')).arg(0, 2, 10, QLatin1Char('0'))); } void TourWidget::finishAddingItem() { GeoDataFeature *feature = d->getPlaylistFeature(); if ( feature ) { emit featureUpdated( feature ); d->updateRootIndex(); } } void TourWidget::moveDown() { d->moveDown(); GeoDataFeature *feature = d->getPlaylistFeature(); if ( feature ) { emit featureUpdated( feature ); d->updateRootIndex(); } } void TourWidget::moveUp() { d->moveUp(); GeoDataFeature *feature = d->getPlaylistFeature(); if ( feature ) { emit featureUpdated( feature ); d->updateRootIndex(); } } GeoDataObject *TourWidgetPrivate::rootIndexObject() const { QModelIndex const rootIndex = m_tourUi.m_listView->rootIndex(); return rootIndex.isValid() ? static_cast( rootIndex.internalPointer() ) : 0; } void TourWidgetPrivate::createTour() { if ( overrideModifications() ) { GeoDataDocument *document = new GeoDataDocument(); document->setDocumentRole( UserDocument ); document->setName(QStringLiteral("New Tour")); document->setId(QStringLiteral("new_tour")); GeoDataTour *tour = new GeoDataTour(); tour->setName(QStringLiteral("New Tour")); GeoDataPlaylist *playlist = new GeoDataPlaylist; tour->setPlaylist( playlist ); document->append( static_cast( tour ) ); m_playback.setBaseUrl( QUrl::fromLocalFile( MarbleDirs::marbleDataPath() ) ); openDocument( document ); m_isChanged = true; m_tourUi.m_actionSaveTour->setEnabled( true ); m_tourUi.m_slider->setEnabled( true ); } } bool TourWidgetPrivate::openDocument(GeoDataDocument* document) { if ( document ) { if ( m_document ) { m_widget->model()->treeModel()->removeDocument( m_document ); delete m_document; } m_document = document; m_widget->model()->treeModel()->addDocument( m_document ); m_isChanged = false; updateRootIndex(); m_addPrimitiveButton->setEnabled( true ); m_tourUi.m_actionSaveTourAs->setEnabled( true ); m_tourUi.m_actionSaveTour->setEnabled( false ); m_isChanged = false; return true; } return false; } void TourWidgetPrivate::saveTour() { if ( m_document ) { if ( !m_document->fileName().isEmpty() ) { saveTourAs( m_document->fileName() ); } else { saveTourAs(); } } } void TourWidgetPrivate::saveTourAs() { if ( m_document ) { QString const filename = QFileDialog::getSaveFileName( q, QObject::tr( "Save Tour as" ), QDir::homePath(), QObject::tr( "KML Tours (*.kml)" ) ); if ( !filename.isEmpty() ) { saveTourAs( filename ); } } } bool TourWidgetPrivate::saveTourAs(const QString &filename) { if ( !filename.isEmpty() ) { if (GeoDataDocumentWriter::write(filename, *m_document)) { m_tourUi.m_actionSaveTour->setEnabled( false ); m_isChanged = false; GeoDataDocument* document = m_document; if ( !document->fileName().isNull() ) { m_widget->model()->removeGeoData( document->fileName() ); } m_widget->model()->addGeoDataFile( filename ); m_document->setFileName( filename ); return true; } } return false; } void TourWidgetPrivate::captureTour() { MarbleWidget* widget = new MarbleWidget; widget->setMapThemeId( m_widget->mapThemeId() ); widget->resize( 1280, 720 ); m_widget->model()->treeModel()->removeDocument(m_document); widget->model()->treeModel()->addDocument(m_document); GeoDataTour* tour = findTour( m_document ); TourPlayback* playback = new TourPlayback; playback->setMarbleWidget( widget ); playback->setTour( tour ); m_tourUi.m_listView->setModel( widget->model()->treeModel() ); if( tour ){ m_tourUi.m_listView->setRootIndex( widget->model()->treeModel()->index( tour->playlist() ) ); m_tourUi.m_listView->repaint(); QPointer tourCaptureDialog = new TourCaptureDialog( widget, m_widget ); tourCaptureDialog->setDefaultFilename( tour->name() ); tourCaptureDialog->setTourPlayback( playback ); tourCaptureDialog->exec(); } delete playback; widget->model()->treeModel()->removeDocument(m_document); m_widget->model()->treeModel()->addDocument(m_document); updateRootIndex(); delete widget; } bool TourWidgetPrivate::overrideModifications() { if ( m_document && m_isChanged ) { QString title = QObject::tr( "Discard Changes" ); QString text = QObject::tr( "Are you sure want to discard all unsaved changes and close current document?" ); QPointer dialog = new QMessageBox( QMessageBox::Question, title, text, QMessageBox::Yes | QMessageBox::No, q ); dialog->setDefaultButton( QMessageBox::No ); if ( dialog->exec() != QMessageBox::Yes ) { delete dialog; return false; } delete dialog; } return true; } bool TourWidget::openTour( const QString &filename) { return d->openFile( filename ); } void TourWidgetPrivate::handlePlaybackProgress(const double position) { if( !m_tourUi.m_slider->isSliderDown() ){ m_tourUi.m_slider->setValue( position * 100 ); QTime nullTime( 0, 0, 0 ); QTime time = nullTime.addSecs( position ); m_tourUi.m_elapsedTime->setText(QString("%L1:%L2").arg(time.minute(), 2, 10, QLatin1Char('0')).arg(time.second(), 2, 10, QLatin1Char('0'))); } } void TourWidget::setHighlightedItemIndex( int index ) { GeoDataObject* rootObject = d->rootIndexObject(); GeoDataPlaylist* playlist = static_cast( rootObject ); QModelIndex playlistIndex = d->m_widget->model()->treeModel()->index( playlist ); // Only flyTo and wait items have duration, so the other types have to be skipped. int searchedIndex = 0; for ( int i = 0; i < playlist->size(); i++ ) { QModelIndex currentIndex = d->m_widget->model()->treeModel()->index( i, 0, playlistIndex ); GeoDataObject* object = qvariant_cast(currentIndex.data( MarblePlacemarkModel::ObjectPointerRole ) ); - if ( object->nodeType() == GeoDataTypes::GeoDataFlyToType - || object->nodeType() == GeoDataTypes::GeoDataWaitType ) + if (geodata_cast(object) + || geodata_cast(object)) ++searchedIndex; if ( index == searchedIndex ) { d->m_tourUi.m_listView->selectionModel()->setCurrentIndex( currentIndex, QItemSelectionModel::NoUpdate ); d->m_tourUi.m_listView->scrollTo( currentIndex ); break; } } d->m_tourUi.m_listView->viewport()->update(); } void TourWidget::removeHighlight() { QModelIndex index; // Restoring the CurrentIndex to the previously selected item // or clearing it if there was no selected item. if ( d->m_tourUi.m_listView->selectionModel()->hasSelection() ) { index = d->m_tourUi.m_listView->selectionModel()->selectedIndexes().last(); } else { index = QModelIndex(); } d->m_tourUi.m_listView->selectionModel()->setCurrentIndex( index, QItemSelectionModel::NoUpdate ); d->m_tourUi.m_listView->viewport()->update(); } bool TourWidget::isPlaying() const { return d->m_playState; } } #include "moc_TourWidget.cpp" diff --git a/src/lib/marble/TreeViewDecoratorModel.cpp b/src/lib/marble/TreeViewDecoratorModel.cpp index 3d2d50d2d..77ad2c82c 100644 --- a/src/lib/marble/TreeViewDecoratorModel.cpp +++ b/src/lib/marble/TreeViewDecoratorModel.cpp @@ -1,93 +1,92 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Levente Kurusa #include "TreeViewDecoratorModel.h" #include "MarbleDebug.h" #include "GeoDataFolder.h" -#include "GeoDataTypes.h" #include "GeoDataObject.h" #include "GeoDataContainer.h" #include "GeoDataStyle.h" #include "GeoDataListStyle.h" #include "GeoDataItemIcon.h" #include "MarblePlacemarkModel.h" #include namespace Marble { TreeViewDecoratorModel::TreeViewDecoratorModel( QObject *parent ) : QSortFilterProxyModel( parent ) { // nothing to do } bool TreeViewDecoratorModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const { QModelIndex rowIndex = sourceModel()->index( sourceRow, 0, sourceParent ); const GeoDataObject* object = qvariant_cast( rowIndex.data( MarblePlacemarkModel::ObjectPointerRole ) ); const GeoDataObject* parent = object->parent(); if (const auto container = dynamic_cast(parent)) { if ( container->style()->listStyle().listItemType() == GeoDataListStyle::CheckHideChildren ) { return false; } } return QSortFilterProxyModel::filterAcceptsRow( sourceRow, sourceParent ); } QVariant TreeViewDecoratorModel::data( const QModelIndex &proxyIndex, int role) const { if ( role != Qt::DecorationRole || proxyIndex.column() != 0 ) { return QSortFilterProxyModel::data(proxyIndex, role); } GeoDataObject *object = qvariant_cast( QSortFilterProxyModel::data(proxyIndex, MarblePlacemarkModel::ObjectPointerRole)); if ( !object ) { return QSortFilterProxyModel::data(proxyIndex, role); } - if ( object->nodeType() != GeoDataTypes::GeoDataFolderType ) { + if (geodata_cast(object)) { return QSortFilterProxyModel::data(proxyIndex, role); } GeoDataFolder *folder = static_cast( object ); bool const expandedState = m_expandedRows.contains( QPersistentModelIndex( proxyIndex ) ); for (GeoDataItemIcon *icon: folder->style()->listStyle().itemIconList()) { if ( ! expandedState ) { if ( icon->state() == GeoDataItemIcon::Closed ) { return icon->icon(); } } else { if ( icon->state() == GeoDataItemIcon::Open ) { return icon->icon(); } } } return QSortFilterProxyModel::data(proxyIndex, role); } void TreeViewDecoratorModel::trackExpandedState( const QModelIndex &index ) { m_expandedRows << QPersistentModelIndex( index ); } void TreeViewDecoratorModel::trackCollapsedState( const QModelIndex &index ) { m_expandedRows.removeAll( QPersistentModelIndex( index )); } } #include "moc_TreeViewDecoratorModel.cpp" diff --git a/src/lib/marble/VectorTileModel.cpp b/src/lib/marble/VectorTileModel.cpp index 9aff43950..f3050a5e2 100644 --- a/src/lib/marble/VectorTileModel.cpp +++ b/src/lib/marble/VectorTileModel.cpp @@ -1,232 +1,230 @@ /* This file is part of the Marble Virtual Globe. This program is free software licensed under the GNU LGPL. You can find a copy of this license in LICENSE.txt in the top directory of the source code. Copyright 2012 Ander Pijoan Copyright 2013 Bernhard Beschow */ #include "VectorTileModel.h" #include "GeoDataDocument.h" #include "GeoDataLatLonBox.h" #include "GeoDataTreeModel.h" -#include "GeoDataTypes.h" #include "GeoSceneVectorTileDataset.h" #include "MarbleGlobal.h" #include "MarbleDebug.h" #include "MathHelper.h" #include "MarbleMath.h" #include "TileId.h" #include "TileLoader.h" #include #include namespace Marble { TileRunner::TileRunner(TileLoader *loader, const GeoSceneVectorTileDataset *tileDataset, const TileId &id) : m_loader(loader), m_tileDataset(tileDataset), m_id(id) { } void TileRunner::run() { GeoDataDocument *const document = m_loader->loadTileVectorData(m_tileDataset, m_id, DownloadBrowse); emit documentLoaded(m_id, document); } VectorTileModel::CacheDocument::CacheDocument(GeoDataDocument *doc, VectorTileModel *vectorTileModel, const GeoDataLatLonBox &boundingBox) : m_document(doc), m_vectorTileModel(vectorTileModel), m_boundingBox(boundingBox) { // nothing to do } VectorTileModel::CacheDocument::~CacheDocument() { m_vectorTileModel->removeTile(m_document); } VectorTileModel::VectorTileModel(TileLoader *loader, const GeoSceneVectorTileDataset *layer, GeoDataTreeModel *treeModel, QThreadPool *threadPool) : m_loader(loader), m_layer(layer), m_treeModel(treeModel), m_threadPool(threadPool), m_tileLoadLevel(-1), m_tileZoomLevel(-1), m_deleteDocumentsLater(false) { connect(this, SIGNAL(tileAdded(GeoDataDocument*)), treeModel, SLOT(addDocument(GeoDataDocument*))); connect(this, SIGNAL(tileRemoved(GeoDataDocument*)), treeModel, SLOT(removeDocument(GeoDataDocument*))); connect(treeModel, SIGNAL(removed(GeoDataObject*)), this, SLOT(cleanupTile(GeoDataObject*))); } void VectorTileModel::setViewport(const GeoDataLatLonBox &latLonBox) { bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; int const nTiles = smallScreen ? 12 : 20; qreal const viewportArea = latLonBox.width() * latLonBox.height(); qreal const level = log((nTiles * 2.0 * M_PI * M_PI) / viewportArea) / log(4); m_tileZoomLevel = qFloor(level); int tileLoadLevel = m_tileZoomLevel; // Determine available tile levels in the layer and thereby // select the tileZoomLevel that is actually used: QVector tileLevels = m_layer->tileLevels(); if (tileLevels.isEmpty() /* || tileZoomLevel < tileLevels.first() */) { // if there is no (matching) tile level then show nothing // and bail out. m_documents.clear(); return; } int tileLevel = tileLevels.first(); for (int i = 1, n = tileLevels.size(); i < n; ++i) { if (tileLevels[i] > tileLoadLevel) { break; } tileLevel = tileLevels[i]; } tileLoadLevel = tileLevel; // if zoom level has changed, empty vectortile cache if (tileLoadLevel != m_tileLoadLevel) { m_deleteDocumentsLater = m_tileLoadLevel >= 0; m_tileLoadLevel = tileLoadLevel; } /** LOGIC FOR DOWNLOADING ALL THE TILES THAT ARE INSIDE THE SCREEN AT THE CURRENT ZOOM LEVEL **/ // New tiles X and Y for moved screen coordinates // More info: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Subtiles // More info: http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#C.2FC.2B.2B const QRect rect = m_layer->tileProjection()->tileIndexes(latLonBox, tileLoadLevel); // Download tiles and send them to VectorTileLayer // When changing zoom, download everything inside the screen // TODO: hardcodes assumption about tiles indexing also ends at dateline // TODO: what about crossing things in y direction? if (!latLonBox.crossesDateLine()) { queryTiles(tileLoadLevel, rect); } // When only moving screen, just download the new tiles else { // TODO: maxTileX (calculation knowledge) should be a property of tileProjection or m_layer const int maxTileX = (1 << tileLoadLevel) * m_layer->levelZeroColumns() - 1; queryTiles(tileLoadLevel, QRect(QPoint(0, rect.top()), rect.bottomRight())); queryTiles(tileLoadLevel, QRect(rect.topLeft(), QPoint(maxTileX, rect.bottom()))); } removeTilesOutOfView(latLonBox); } void VectorTileModel::removeTilesOutOfView(const GeoDataLatLonBox &boundingBox) { GeoDataLatLonBox const extendedViewport = boundingBox.scaled(2.0, 2.0); for (auto iter = m_documents.begin(); iter != m_documents.end();) { bool const isOutOfView = !extendedViewport.intersects(iter.value()->m_boundingBox); if (isOutOfView) { iter = m_documents.erase(iter); } else { ++iter; } } } QString VectorTileModel::name() const { return m_layer->name(); } void VectorTileModel::removeTile(GeoDataDocument *document) { emit tileRemoved(document); } int VectorTileModel::tileZoomLevel() const { return m_tileZoomLevel; } int VectorTileModel::cachedDocuments() const { return m_documents.size(); } void VectorTileModel::reload() { for (auto const &tile : m_documents.keys()) { m_loader->downloadTile(m_layer, tile, DownloadBrowse); } } void VectorTileModel::updateTile(const TileId &idWithMapThemeHash, GeoDataDocument *document) { TileId const id(0, idWithMapThemeHash.zoomLevel(), idWithMapThemeHash.x(), idWithMapThemeHash.y()); m_pendingDocuments.removeAll(id); if (!document) { return; } if (m_tileLoadLevel != id.zoomLevel()) { delete document; return; } document->setName(QString("%1/%2/%3").arg(id.zoomLevel()).arg(id.x()).arg(id.y())); m_garbageQueue << document; if (m_documents.contains(id)) { m_documents.remove(id); } if (m_deleteDocumentsLater) { m_deleteDocumentsLater = false; m_documents.clear(); } const GeoDataLatLonBox boundingBox = m_layer->tileProjection()->geoCoordinates(id); m_documents[id] = QSharedPointer(new CacheDocument(document, this, boundingBox)); emit tileAdded(document); } void VectorTileModel::clear() { m_documents.clear(); } void VectorTileModel::queryTiles(int tileZoomLevel, const QRect &rect) { // Download all the tiles inside the given indexes for (int x = rect.left(); x <= rect.right(); ++x) { for (int y = rect.top(); y <= rect.bottom(); ++y) { const TileId tileId = TileId(0, tileZoomLevel, x, y); if (!m_documents.contains(tileId) && !m_pendingDocuments.contains(tileId)) { m_pendingDocuments << tileId; TileRunner *job = new TileRunner(m_loader, m_layer, tileId); connect(job, SIGNAL(documentLoaded(TileId, GeoDataDocument*)), this, SLOT(updateTile(TileId, GeoDataDocument*))); m_threadPool->start(job); } } } } void VectorTileModel::cleanupTile(GeoDataObject *object) { - if (object->nodeType() == GeoDataTypes::GeoDataDocumentType) { - GeoDataDocument* document = static_cast(object); + if (GeoDataDocument *document = geodata_cast(object)) { if (m_garbageQueue.contains(document)) { m_garbageQueue.removeAll(document); delete document; } } } } #include "moc_VectorTileModel.cpp" diff --git a/src/lib/marble/WaitEditWidget.cpp b/src/lib/marble/WaitEditWidget.cpp index 20bccca3a..d43e66e5d 100644 --- a/src/lib/marble/WaitEditWidget.cpp +++ b/src/lib/marble/WaitEditWidget.cpp @@ -1,81 +1,81 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2013 Mihail Ivchenko // Copyright 2014 Sanjiban Bairagya // Copyright 2014 Illya Kovalevskyy // #include #include #include #include #include "WaitEditWidget.h" #include "MarblePlacemarkModel.h" -#include "GeoDataTypes.h" #include "GeoDataTourControl.h" #include "geodata/data/GeoDataWait.h" namespace Marble { WaitEditWidget::WaitEditWidget( const QModelIndex &index, QWidget *parent ) : QWidget( parent ), m_index( index ), m_spinBox( new QDoubleSpinBox ), m_button( new QToolButton ) { QHBoxLayout *layout = new QHBoxLayout; layout->setSpacing( 5 ); QLabel* iconLabel = new QLabel; iconLabel->setPixmap(QPixmap(QStringLiteral(":/marble/player-time.png"))); layout->addWidget( iconLabel ); QLabel *waitLabel = new QLabel; waitLabel->setText( tr( "Wait duration:" ) ); layout->addWidget( waitLabel ); layout->addWidget( m_spinBox ); m_spinBox->setValue( waitElement()->duration() ); m_spinBox->setSuffix( tr(" s", "seconds") ); m_button->setIcon(QIcon(QStringLiteral(":/marble/document-save.png"))); connect(m_button, SIGNAL(clicked()), this, SLOT(save())); layout->addWidget( m_button ); setLayout( layout ); } bool WaitEditWidget::editable() const { return m_button->isEnabled(); } void WaitEditWidget::setEditable( bool editable ) { m_button->setEnabled( editable ); } void WaitEditWidget::save() { waitElement()->setDuration( m_spinBox->value() ); emit editingDone(m_index); } GeoDataWait* WaitEditWidget::waitElement() { GeoDataObject *object = qvariant_cast(m_index.data( MarblePlacemarkModel::ObjectPointerRole ) ); Q_ASSERT( object ); - Q_ASSERT( object->nodeType() == GeoDataTypes::GeoDataWaitType ); - return static_cast( object ); + auto wait = geodata_cast(object); + Q_ASSERT(wait); + return wait; } } // namespace Marble #include "moc_WaitEditWidget.cpp" diff --git a/src/lib/marble/declarative/Bookmarks.cpp b/src/lib/marble/declarative/Bookmarks.cpp index e920e804d..a31d29c1a 100644 --- a/src/lib/marble/declarative/Bookmarks.cpp +++ b/src/lib/marble/declarative/Bookmarks.cpp @@ -1,218 +1,217 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2012 Dennis Nienhüser // #include "Bookmarks.h" #include "Planet.h" #include "MarbleQuickItem.h" #include "MarbleModel.h" #include "MarbleMath.h" #include "MarblePlacemarkModel.h" #include "BookmarkManager.h" #include "GeoDataDocument.h" #include "GeoDataPlacemark.h" #include "GeoDataFolder.h" #include "GeoDataTypes.h" #include "GeoDataExtendedData.h" #include "GeoDataTreeModel.h" #include "kdescendantsproxymodel.h" #include "osm/OsmPlacemarkData.h" #include namespace Marble { Bookmarks::Bookmarks( QObject* parent ) : QObject( parent ), m_marbleQuickItem( 0 ), m_proxyModel( 0 ) { // nothing to do } MarbleQuickItem *Bookmarks::map() { return m_marbleQuickItem; } void Bookmarks::setMap( MarbleQuickItem* item ) { m_marbleQuickItem = item; if (item) { connect(item->model()->bookmarkManager(), SIGNAL(bookmarksChanged()), this, SLOT(updateBookmarkDocument())); } updateBookmarkDocument(); emit modelChanged(); } bool Bookmarks::isBookmark( qreal longitude, qreal latitude ) const { if ( !m_marbleQuickItem || !m_marbleQuickItem->model()->bookmarkManager() ) { return false; } Marble::BookmarkManager* manager = m_marbleQuickItem->model()->bookmarkManager(); Marble::GeoDataDocument *bookmarks = manager->document(); Marble::GeoDataCoordinates const compareTo( longitude, latitude, 0.0, Marble::GeoDataCoordinates::Degree ); qreal planetRadius = m_marbleQuickItem->model()->planet()->radius(); for( const Marble::GeoDataFolder* folder: bookmarks->folderList() ) { for( const Marble::GeoDataPlacemark * const placemark: folder->placemarkList() ) { if ( distanceSphere( placemark->coordinate(), compareTo ) * planetRadius < 5 ) { return true; } } } return false; } Placemark *Bookmarks::placemark(int row) { Placemark* placemark = new Placemark; QModelIndex index = model()->index(row, 0); GeoDataObject *object = model()->data(index, MarblePlacemarkModel::ObjectPointerRole ).value(); - if (object->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - GeoDataPlacemark *geoDataPlacemark = static_cast(object); + if (GeoDataPlacemark *geoDataPlacemark = geodata_cast(object)) { placemark->setGeoDataPlacemark(*geoDataPlacemark); } return placemark; } void Bookmarks::addBookmark(Placemark *placemark, const QString &folderName ) { if ( !m_marbleQuickItem || !m_marbleQuickItem->model()->bookmarkManager() ) { return; } Marble::BookmarkManager* manager = m_marbleQuickItem->model()->bookmarkManager(); Marble::GeoDataDocument *bookmarks = manager->document(); Marble::GeoDataContainer *target = 0; for( Marble::GeoDataFolder* const folder: bookmarks->folderList() ) { if ( folder->name() == folderName ) { target = folder; break; } } if ( !target ) { manager->addNewBookmarkFolder( bookmarks, folderName ); for( Marble::GeoDataFolder* const folder: bookmarks->folderList() ) { if ( folder->name() == folderName ) { target = folder; break; } } Q_ASSERT( target ); } Marble::GeoDataPlacemark bookmark = placemark->placemark(); if (bookmark.name().isEmpty()) { bookmark.setName(placemark->address()); } if (bookmark.name().isEmpty()) { bookmark.setName(bookmark.coordinate().toString(GeoDataCoordinates::Decimal).trimmed()); } bookmark.clearOsmData(); bookmark.setCoordinate(bookmark.coordinate()); // replace non-point geometries with their center manager->addBookmark( target, bookmark ); } void Bookmarks::removeBookmark( qreal longitude, qreal latitude ) { if ( !m_marbleQuickItem || !m_marbleQuickItem->model()->bookmarkManager() ) { return; } Marble::BookmarkManager* manager = m_marbleQuickItem->model()->bookmarkManager(); Marble::GeoDataDocument *bookmarks = manager->document(); Marble::GeoDataCoordinates const compareTo( longitude, latitude, 0.0, Marble::GeoDataCoordinates::Degree ); qreal planetRadius = m_marbleQuickItem->model()->planet()->radius(); for( const Marble::GeoDataFolder* folder: bookmarks->folderList() ) { for( Marble::GeoDataPlacemark * placemark: folder->placemarkList() ) { if ( distanceSphere( placemark->coordinate(), compareTo ) * planetRadius < 5 ) { manager->removeBookmark( placemark ); return; } } } } void Bookmarks::updateBookmarkDocument() { if (m_marbleQuickItem) { Marble::BookmarkManager* manager = m_marbleQuickItem->model()->bookmarkManager(); m_treeModel.setRootDocument( manager->document() ); } } BookmarksModel *Bookmarks::model() { if ( !m_proxyModel && m_marbleQuickItem && m_marbleQuickItem->model()->bookmarkManager() ) { KDescendantsProxyModel* flattener = new KDescendantsProxyModel( this ); flattener->setSourceModel(&m_treeModel); m_proxyModel = new BookmarksModel( this ); m_proxyModel->setFilterFixedString( Marble::GeoDataTypes::GeoDataPlacemarkType ); m_proxyModel->setFilterKeyColumn( 1 ); m_proxyModel->setSourceModel( flattener ); } return m_proxyModel; } BookmarksModel::BookmarksModel( QObject *parent ) : QSortFilterProxyModel( parent ) { connect( this, SIGNAL(layoutChanged()), this, SIGNAL(countChanged()) ); connect( this, SIGNAL(modelReset()), this, SIGNAL(countChanged()) ); connect( this, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged()) ); connect( this, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged()) ); } int BookmarksModel::count() const { return rowCount(); } qreal BookmarksModel::longitude( int idx ) const { if ( idx >= 0 && idx < rowCount() ) { QVariant const value = data( index( idx, 0 ), Marble::MarblePlacemarkModel::CoordinateRole ); Marble::GeoDataCoordinates const coordinates = value.value(); return coordinates.longitude( Marble::GeoDataCoordinates::Degree ); } return 0.0; } qreal BookmarksModel::latitude( int idx ) const { if ( idx >= 0 && idx < rowCount() ) { QVariant const value = data( index( idx, 0 ), Marble::MarblePlacemarkModel::CoordinateRole ); Marble::GeoDataCoordinates const coordinates = value.value(); return coordinates.latitude( Marble::GeoDataCoordinates::Degree ); } return 0.0; } QString BookmarksModel::name( int idx ) const { if ( idx >= 0 && idx < rowCount() ) { return data( index( idx, 0 ) ).toString(); } return QString(); } } #include "moc_Bookmarks.cpp" diff --git a/src/lib/marble/declarative/MarbleQuickItem.cpp b/src/lib/marble/declarative/MarbleQuickItem.cpp index 8f18c3598..dfcf38a0b 100644 --- a/src/lib/marble/declarative/MarbleQuickItem.cpp +++ b/src/lib/marble/declarative/MarbleQuickItem.cpp @@ -1,1013 +1,1012 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Adam Dabrowski // #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 #include #include #include "GeoDataRelation.h" #include "osm/OsmPlacemarkData.h" #include "GeoDataDocument.h" namespace Marble { //TODO - move to separate files class QuickItemSelectionRubber : public AbstractSelectionRubber { //TODO: support rubber selection in MarbleQuickItem public: QuickItemSelectionRubber(); void show() override { m_visible = true; } void hide() override { m_visible = false; } bool isVisible() const override { return m_visible; } const QRect &geometry() const override { return m_geometry; } void setGeometry(const QRect &/*geometry*/) override {} private: QRect m_geometry; bool m_visible; }; //TODO - implement missing functionalities class MarbleQuickInputHandler : public MarbleDefaultInputHandler { public: MarbleQuickInputHandler(MarbleAbstractPresenter *marblePresenter, MarbleQuickItem *marbleQuick) : MarbleDefaultInputHandler(marblePresenter) ,m_marbleQuick(marbleQuick) { setInertialEarthRotationEnabled(false); //Disabled by default, it's buggy. TODO - fix } bool acceptMouse() override { return true; } void pinch(QPointF center, qreal scale, Qt::GestureState state) { //TODO - this whole thing should be moved to MarbleAbstractPresenter (void)handlePinch(center, scale, state); } void handleMouseButtonPressAndHold(const QPoint &position) override { m_marbleQuick->reverseGeocoding(position); } private Q_SLOTS: void showLmbMenu(int x, int y) override { m_marbleQuick->selectPlacemarkAt(x, y); } void showRmbMenu(int, int) override {} void openItemToolTip() override {} void setCursor(const QCursor &cursor) override { m_marbleQuick->setCursor(cursor); } private Q_SLOTS: void installPluginEventFilter(RenderPlugin *) override {} private: bool layersEventFilter(QObject *o, QEvent *e) override { return m_marbleQuick->layersEventFilter(o, e); } //empty - don't check. It would be invalid with quick items void checkReleasedMove(QMouseEvent *) override {} bool handleTouch(QTouchEvent *event) override { if (event->touchPoints().count() > 1) { //not handling multi-touch at all, let PinchArea or MultiPointTouchArea take care of it return false; } if (event->touchPoints().count() == 1) { //handle - but do not accept. I.e. pinchArea still needs to get this QTouchEvent::TouchPoint p = event->touchPoints().at(0); if (event->type() == QEvent::TouchBegin) { QMouseEvent press(QMouseEvent::MouseButtonPress, p.pos(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); handleMouseEvent(&press); } else if (event->type() == QEvent::TouchUpdate) { QMouseEvent move(QMouseEvent::MouseMove, p.pos(), Qt::NoButton, Qt::LeftButton, Qt::NoModifier); handleMouseEvent(&move); } else if (event->type() == QEvent::TouchEnd) { QMouseEvent release(QMouseEvent::MouseButtonRelease, p.pos(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); handleMouseEvent(&release); } } return false; } AbstractSelectionRubber *selectionRubber() override { return &m_selectionRubber; } MarbleQuickItem *m_marbleQuick; QuickItemSelectionRubber m_selectionRubber; bool m_usePinchArea; }; class MarbleQuickItemPrivate { public: explicit MarbleQuickItemPrivate(MarbleQuickItem *marble) : m_marble(marble), m_model(), m_map(&m_model), m_presenter(&m_map), m_positionVisible(false), m_currentPosition(marble), m_inputHandler(&m_presenter, marble), m_placemarkDelegate(nullptr), m_placemarkItem(nullptr), m_placemark(nullptr), m_reverseGeocoding(&m_model), m_showScaleBar(false) { m_currentPosition.setName(QObject::tr("Current Location")); } private: MarbleQuickItem *m_marble; friend class MarbleQuickItem; MarbleModel m_model; MarbleMap m_map; MarbleAbstractPresenter m_presenter; bool m_positionVisible; Placemark m_currentPosition; MarbleQuickInputHandler m_inputHandler; QQmlComponent* m_placemarkDelegate; QQuickItem* m_placemarkItem; Placemark* m_placemark; ReverseGeocodingRunnerManager m_reverseGeocoding; bool m_showScaleBar; }; MarbleQuickItem::MarbleQuickItem(QQuickItem *parent) : QQuickPaintedItem(parent) ,d(new MarbleQuickItemPrivate(this)) { setRenderTarget(QQuickPaintedItem::FramebufferObject); setOpaquePainting(true); qRegisterMetaType("Placemark*"); for (AbstractFloatItem *item: d->m_map.floatItems()) { if (item->nameId() == QLatin1String("license")) { item->setPosition(QPointF(5.0, -10.0)); } else { item->hide(); } } d->m_model.positionTracking()->setTrackVisible(false); connect(&d->m_map, SIGNAL(repaintNeeded(QRegion)), this, SLOT(update())); connect(this, &MarbleQuickItem::widthChanged, this, &MarbleQuickItem::resizeMap); connect(this, &MarbleQuickItem::heightChanged, this, &MarbleQuickItem::resizeMap); connect(&d->m_map, &MarbleMap::visibleLatLonAltBoxChanged, this, &MarbleQuickItem::updatePositionVisibility); connect(&d->m_map, &MarbleMap::visibleLatLonAltBoxChanged, this, &MarbleQuickItem::visibleLatLonAltBoxChanged); connect(&d->m_map, &MarbleMap::radiusChanged, this, &MarbleQuickItem::radiusChanged); connect(&d->m_map, &MarbleMap::radiusChanged, this, &MarbleQuickItem::zoomChanged); connect(&d->m_map, &MarbleMap::showPublicTransportChanged, this, &MarbleQuickItem::showPublicTransportChanged); connect(&d->m_reverseGeocoding, SIGNAL(reverseGeocodingFinished(GeoDataCoordinates,GeoDataPlacemark)), this, SLOT(handleReverseGeocoding(GeoDataCoordinates,GeoDataPlacemark))); setAcceptedMouseButtons(Qt::AllButtons); installEventFilter(&d->m_inputHandler); } void MarbleQuickItem::resizeMap() { d->m_map.setSize(qMax(100, int(width())), qMax(100, int(height()))); update(); updatePositionVisibility(); } void MarbleQuickItem::positionDataStatusChanged(PositionProviderStatus status) { bool const positionAvailable = status == PositionProviderStatusAvailable; emit positionAvailableChanged(positionAvailable); updatePositionVisibility(); } void MarbleQuickItem::positionChanged(const GeoDataCoordinates &, GeoDataAccuracy) { updatePositionVisibility(); } void MarbleQuickItem::updatePositionVisibility() { updatePlacemarks(); bool isVisible = false; if ( positionAvailable() ) { qreal x, y; bool globeHidesPoint; bool const valid = d->m_map.viewport()->screenCoordinates(d->m_model.positionTracking()->currentLocation(), x, y, globeHidesPoint); isVisible = valid && !globeHidesPoint; } if ( isVisible != d->m_positionVisible ) { d->m_positionVisible = isVisible; emit positionVisibleChanged( isVisible ); } } void MarbleQuickItem::updateCurrentPosition(const GeoDataCoordinates &coordinates) { d->m_currentPosition.placemark().setCoordinate(coordinates); emit currentPositionChanged(&d->m_currentPosition); } void MarbleQuickItem::updatePlacemarks() { if (!d->m_placemarkDelegate || !d->m_placemark) { return; } if (!d->m_placemarkItem) { QQmlContext * context = new QQmlContext(qmlContext(d->m_placemarkDelegate)); QObject * component = d->m_placemarkDelegate->create(context); d->m_placemarkItem = qobject_cast( component ); if (d->m_placemarkItem) { d->m_placemarkItem->setParentItem( this ); d->m_placemarkItem->setProperty("placemark", QVariant::fromValue(d->m_placemark)); } else { delete component; return; } } qreal x = 0; qreal y = 0; const bool visible = d->m_map.viewport()->screenCoordinates(d->m_placemark->placemark().coordinate(), x, y); d->m_placemarkItem->setVisible(visible); if (visible) { d->m_placemarkItem->setProperty("xPos", QVariant(x)); d->m_placemarkItem->setProperty("yPos", QVariant(y)); } } void MarbleQuickItem::handleReverseGeocoding(const GeoDataCoordinates &coordinates, const GeoDataPlacemark &placemark) { if (d->m_placemark && d->m_placemark->placemark().coordinate() == coordinates) { d->m_placemark->setGeoDataPlacemark(placemark); updatePlacemarks(); } } void MarbleQuickItem::paint(QPainter *painter) { //TODO - much to be done here still, i.e paint !enabled version QPaintDevice *paintDevice = painter->device(); QRect rect = contentsBoundingRect().toRect(); painter->end(); { GeoPainter geoPainter(paintDevice, d->m_map.viewport(), d->m_map.mapQuality()); d->m_map.paint(geoPainter, rect); } painter->begin(paintDevice); } void MarbleQuickItem::classBegin() { } void MarbleQuickItem::componentComplete() { } int MarbleQuickItem::mapWidth() const { return d->m_map.width(); } int MarbleQuickItem::mapHeight() const { return d->m_map.height(); } bool MarbleQuickItem::showFrameRate() const { return d->m_map.showFrameRate(); } MarbleQuickItem::Projection MarbleQuickItem::projection() const { return Projection(d->m_map.projection()); } QString MarbleQuickItem::mapThemeId() const { return d->m_map.mapThemeId(); } bool MarbleQuickItem::showAtmosphere() const { return d->m_map.showAtmosphere(); } bool MarbleQuickItem::showCompass() const { return d->m_map.showCompass(); } bool MarbleQuickItem::showClouds() const { return d->m_map.showClouds(); } bool MarbleQuickItem::showCrosshairs() const { return d->m_map.showCrosshairs(); } bool MarbleQuickItem::showGrid() const { return d->m_map.showGrid(); } bool MarbleQuickItem::showOverviewMap() const { return d->m_map.showOverviewMap(); } bool MarbleQuickItem::showOtherPlaces() const { return d->m_map.showOtherPlaces(); } bool MarbleQuickItem::showScaleBar() const { return d->m_showScaleBar; } bool MarbleQuickItem::showBackground() const { return d->m_map.showBackground(); } bool MarbleQuickItem::showPositionMarker() const { QList plugins = d->m_map.renderPlugins(); for (const RenderPlugin * plugin: plugins) { if (plugin->nameId() == QLatin1String("positionMarker")) { return plugin->visible(); } } return false; } bool MarbleQuickItem::showPublicTransport() const { return d->m_map.showPublicTransport(); } QString MarbleQuickItem::positionProvider() const { if ( d->m_model.positionTracking()->positionProviderPlugin() ) { return d->m_model.positionTracking()->positionProviderPlugin()->nameId(); } return QString(); } MarbleModel* MarbleQuickItem::model() { return &d->m_model; } const MarbleModel* MarbleQuickItem::model() const { return &d->m_model; } MarbleMap* MarbleQuickItem::map() { return &d->m_map; } const MarbleMap* MarbleQuickItem::map() const { return &d->m_map; } bool MarbleQuickItem::inertialGlobeRotation() const { return d->m_inputHandler.inertialEarthRotationEnabled(); } bool MarbleQuickItem::animationViewContext() const { return d->m_map.viewContext() == Animation; } QQmlComponent *MarbleQuickItem::placemarkDelegate() const { return d->m_placemarkDelegate; } void MarbleQuickItem::reverseGeocoding(const QPoint &point) { qreal lon, lat; d->m_map.viewport()->geoCoordinates(point.x(), point.y(), lon, lat); auto const coordinates = GeoDataCoordinates(lon, lat, 0.0, GeoDataCoordinates::Degree); delete d->m_placemarkItem; d->m_placemarkItem = nullptr; delete d->m_placemark; d->m_placemark = new Placemark(this); d->m_placemark->placemark().setCoordinate(coordinates); d->m_reverseGeocoding.reverseGeocoding(coordinates); } qreal MarbleQuickItem::speed() const { return d->m_model.positionTracking()->speed(); } qreal MarbleQuickItem::angle() const { bool routeExists = d->m_model.routingManager()->routingModel()->route().distance() != 0.0; bool onRoute = !d->m_model.routingManager()->routingModel()->deviatedFromRoute(); if ( routeExists && onRoute) { GeoDataCoordinates curPoint = d->m_model.positionTracking()->positionProviderPlugin()->position(); return d->m_model.routingManager()->routingModel()->route().currentSegment().projectedDirection(curPoint); } else { return d->m_model.positionTracking()->direction(); } } bool MarbleQuickItem::positionAvailable() const { return d->m_model.positionTracking()->status() == PositionProviderStatusAvailable; } bool MarbleQuickItem::positionVisible() { return d->m_positionVisible; } qreal MarbleQuickItem::distanceFromPointToCurrentLocation(const QPoint & position) const { if ( positionAvailable() ) { qreal lon1; qreal lat1; d->m_map.viewport()->geoCoordinates(position.x(), position.y(), lon1, lat1, GeoDataCoordinates::Radian ); GeoDataCoordinates currentCoordinates = d->m_model.positionTracking()->currentLocation(); qreal lon2 = currentCoordinates.longitude(); qreal lat2 = currentCoordinates.latitude(); return distanceSphere(lon1, lat1, lon2, lat2) * d->m_model.planetRadius(); } return 0; } qreal MarbleQuickItem::angleFromPointToCurrentLocation( const QPoint & position ) const { if ( positionAvailable() ) { qreal x, y; PositionTracking const * positionTracking = d->m_model.positionTracking(); map()->viewport()->screenCoordinates( positionTracking->currentLocation(), x, y ); return atan2( y-position.y(), x-position.x() ) * RAD2DEG; } return 0; } Placemark * MarbleQuickItem::currentPosition() const { return &d->m_currentPosition; } QPointF MarbleQuickItem::screenCoordinatesFromCoordinate(Coordinate * coordinate) const { qreal x; qreal y; d->m_map.viewport()->screenCoordinates(coordinate->coordinates(), x, y); return QPointF(x, y); } void MarbleQuickItem::setRadius(int radius) { d->m_map.setRadius(radius); } void MarbleQuickItem::setZoom(int newZoom, FlyToMode mode) { d->m_presenter.setZoom(newZoom, mode); } void MarbleQuickItem::setZoomToMaximumLevel() { d->m_presenter.setZoom(d->m_map.maximumZoom()); } void MarbleQuickItem::centerOn(const GeoDataPlacemark& placemark, bool animated) { d->m_presenter.centerOn(placemark, animated); } void MarbleQuickItem::centerOn(const GeoDataLatLonBox& box, bool animated) { d->m_presenter.centerOn(box, animated); } void MarbleQuickItem::centerOn(const GeoDataCoordinates &coordinate) { GeoDataLookAt target = d->m_presenter.lookAt(); target.setCoordinates(coordinate); d->m_presenter.flyTo(target, Automatic); } void MarbleQuickItem::centerOn(qreal longitude, qreal latitude) { d->m_presenter.centerOn(longitude, latitude); } void MarbleQuickItem::centerOnCoordinates(qreal longitude, qreal latitude) { centerOn(longitude, latitude); } void MarbleQuickItem::centerOnCurrentPosition() { GeoDataCoordinates coordinates = d->m_model.positionTracking()->currentLocation(); if ( coordinates == GeoDataCoordinates() ) { return; } d->m_presenter.centerOn(coordinates, true); if (d->m_presenter.zoom() < 3000) { d->m_presenter.setZoom(3500); } } void MarbleQuickItem::selectPlacemarkAt(int x, int y) { auto features = d->m_map.whichFeatureAt(QPoint(x, y)); QVector placemarks; for(auto feature: features) { - if (feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - placemarks << static_cast(feature); + if (const auto placemark = geodata_cast(feature)) { + placemarks << placemark; } } for(auto placemark: placemarks) { if (d->m_placemark && placemark->coordinate() == d->m_placemark->placemark().coordinate()) { d->m_placemark->deleteLater(); d->m_placemark = nullptr; } else { if (d->m_placemark) { d->m_placemark->deleteLater(); } d->m_placemark = new Placemark(this); d->m_placemark->setGeoDataPlacemark(*placemark); } delete d->m_placemarkItem; d->m_placemarkItem = nullptr; updatePlacemarks(); return; } if (d->m_placemark) { d->m_placemark->deleteLater(); d->m_placemark = nullptr; delete d->m_placemarkItem; d->m_placemarkItem = nullptr; updatePlacemarks(); } } void MarbleQuickItem::goHome() { d->m_presenter.goHome(); } void MarbleQuickItem::zoomIn(FlyToMode mode) { d->m_presenter.zoomIn(mode); } void MarbleQuickItem::zoomOut(FlyToMode mode) { d->m_presenter.zoomOut(mode); } void MarbleQuickItem::handlePinchStarted(const QPointF &point) { pinch(point, 1, Qt::GestureStarted); } void MarbleQuickItem::handlePinchFinished(const QPointF &point) { pinch(point, 1, Qt::GestureFinished); } void MarbleQuickItem::handlePinchUpdated(const QPointF &point, qreal scale) { scale = sqrt(sqrt(scale)); scale = qBound(static_cast(0.5), scale, static_cast(2.0)); pinch(point, scale, Qt::GestureUpdated); } void MarbleQuickItem::setMapWidth(int mapWidth) { if (d->m_map.width() == mapWidth) { return; } d->m_map.setSize(mapWidth, mapHeight()); emit mapWidthChanged(mapWidth); } void MarbleQuickItem::setMapHeight(int mapHeight) { if (this->mapHeight() == mapHeight) { return; } d->m_map.setSize(mapWidth(), mapHeight); emit mapHeightChanged(mapHeight); } void MarbleQuickItem::setShowFrameRate(bool showFrameRate) { if (this->showFrameRate() == showFrameRate) { return; } d->m_map.setShowFrameRate(showFrameRate); emit showFrameRateChanged(showFrameRate); } void MarbleQuickItem::setProjection(Projection projection) { if (this->projection() == projection) { return; } d->m_map.setProjection(Marble::Projection(projection)); emit projectionChanged(projection); } void MarbleQuickItem::setMapThemeId(const QString& mapThemeId) { if (this->mapThemeId() == mapThemeId) { return; } bool const showCompass = d->m_map.showCompass(); bool const showOverviewMap = d->m_map.showOverviewMap(); bool const showOtherPlaces = d->m_map.showOtherPlaces(); bool const showGrid = d->m_map.showGrid(); d->m_map.setMapThemeId(mapThemeId); // Map themes are allowed to change properties. Enforce ours. d->m_map.setShowCompass(showCompass); d->m_map.setShowOverviewMap(showOverviewMap); d->m_map.setShowOtherPlaces(showOtherPlaces); d->m_map.setShowGrid(showGrid); d->m_map.setShowScaleBar(d->m_showScaleBar); emit mapThemeIdChanged(mapThemeId); } void MarbleQuickItem::setShowAtmosphere(bool showAtmosphere) { if (this->showAtmosphere() == showAtmosphere) { return; } d->m_map.setShowAtmosphere(showAtmosphere); emit showAtmosphereChanged(showAtmosphere); } void MarbleQuickItem::setShowCompass(bool showCompass) { if (this->showCompass() == showCompass) { return; } d->m_map.setShowCompass(showCompass); emit showCompassChanged(showCompass); } void MarbleQuickItem::setShowClouds(bool showClouds) { if (this->showClouds() == showClouds) { return; } d->m_map.setShowClouds(showClouds); emit showCloudsChanged(showClouds); } void MarbleQuickItem::setShowCrosshairs(bool showCrosshairs) { if (this->showCrosshairs() == showCrosshairs) { return; } d->m_map.setShowCrosshairs(showCrosshairs); emit showCrosshairsChanged(showCrosshairs); } void MarbleQuickItem::setShowGrid(bool showGrid) { if (this->showGrid() == showGrid) { return; } d->m_map.setShowGrid(showGrid); emit showGridChanged(showGrid); } void MarbleQuickItem::setShowOverviewMap(bool showOverviewMap) { if (this->showOverviewMap() == showOverviewMap) { return; } d->m_map.setShowOverviewMap(showOverviewMap); emit showOverviewMapChanged(showOverviewMap); } void MarbleQuickItem::setShowOtherPlaces(bool showOtherPlaces) { if (this->showOtherPlaces() == showOtherPlaces) { return; } d->m_map.setShowOtherPlaces(showOtherPlaces); emit showOtherPlacesChanged(showOtherPlaces); } void MarbleQuickItem::setShowScaleBar(bool showScaleBar) { if (d->m_showScaleBar == showScaleBar) { return; } d->m_showScaleBar = showScaleBar; d->m_map.setShowScaleBar(d->m_showScaleBar); emit showScaleBarChanged(showScaleBar); } void MarbleQuickItem::setShowBackground(bool showBackground) { if (this->showBackground() == showBackground) { return; } d->m_map.setShowBackground(showBackground); emit showBackgroundChanged(showBackground); } void MarbleQuickItem::setShowPositionMarker(bool showPositionMarker) { if (this->showPositionMarker() == showPositionMarker) { return; } QList plugins = d->m_map.renderPlugins(); for ( RenderPlugin * plugin: plugins ) { if (plugin->nameId() == QLatin1String("positionMarker")) { plugin->setVisible(showPositionMarker); break; } } emit showPositionMarkerChanged(showPositionMarker); } void MarbleQuickItem::setShowPublicTransport(bool enabled) { d->m_map.setShowPublicTransport(enabled); } void MarbleQuickItem::setPositionProvider(const QString &positionProvider) { QString name; if ( d->m_model.positionTracking()->positionProviderPlugin() ) { name = d->m_model.positionTracking()->positionProviderPlugin()->nameId(); if ( name == positionProvider ) { return; } } if ( positionProvider.isEmpty() ) { d->m_model.positionTracking()->setPositionProviderPlugin( nullptr ); return; } QList plugins = d->m_model.pluginManager()->positionProviderPlugins(); for (const PositionProviderPlugin* plugin: plugins) { if ( plugin->nameId() == positionProvider) { PositionProviderPlugin * newPlugin = plugin->newInstance(); d->m_model.positionTracking()->setPositionProviderPlugin(newPlugin); connect(newPlugin, SIGNAL(statusChanged(PositionProviderStatus)), this, SLOT(positionDataStatusChanged(PositionProviderStatus))); connect(newPlugin, SIGNAL(positionChanged(GeoDataCoordinates,GeoDataAccuracy)), this, SLOT(updateCurrentPosition(GeoDataCoordinates))); connect(newPlugin, SIGNAL(positionChanged(GeoDataCoordinates,GeoDataAccuracy)), this, SIGNAL(speedChanged())); connect(newPlugin, SIGNAL(positionChanged(GeoDataCoordinates,GeoDataAccuracy)), this, SIGNAL(angleChanged())); emit positionProviderChanged(positionProvider); break; } } } void MarbleQuickItem::setInertialGlobeRotation(bool inertialGlobeRotation) { if (inertialGlobeRotation == d->m_inputHandler.inertialEarthRotationEnabled()) { return; } d->m_inputHandler.setInertialEarthRotationEnabled(inertialGlobeRotation); emit inertialGlobeRotationChanged(inertialGlobeRotation); } void MarbleQuickItem::setAnimationViewContext(bool animationViewContext) { d->m_map.setViewContext(animationViewContext ? Animation : Still ); emit inertialGlobeRotationChanged(animationViewContext); } void MarbleQuickItem::setPluginSetting(const QString &pluginId, const QString &key, const QString &value) { for (RenderPlugin* plugin: d->m_map.renderPlugins()) { if (plugin->nameId() == pluginId) { plugin->setSetting(key, value); } } } void MarbleQuickItem::setPropertyEnabled(const QString &property, bool enabled) { d->m_map.setPropertyValue(property, enabled); } bool MarbleQuickItem::isPropertyEnabled(const QString &property) const { return d->m_map.propertyValue(property); } void MarbleQuickItem::setShowRuntimeTrace(bool showRuntimeTrace) { d->m_map.setShowRuntimeTrace(showRuntimeTrace); update(); } void MarbleQuickItem::setShowDebugPolygons(bool showDebugPolygons) { d->m_map.setShowDebugPolygons(showDebugPolygons); update(); } void MarbleQuickItem::setShowDebugPlacemarks(bool showDebugPlacemarks) { d->m_map.setShowDebugPlacemarks(showDebugPlacemarks); update(); } void MarbleQuickItem::setShowDebugBatches(bool showDebugBatches) { d->m_map.setShowDebugBatchRender(showDebugBatches); update(); } void MarbleQuickItem::setPlacemarkDelegate(QQmlComponent *placemarkDelegate) { if (d->m_placemarkDelegate == placemarkDelegate) { return; } delete d->m_placemarkItem; d->m_placemarkItem = nullptr; d->m_placemarkDelegate = placemarkDelegate; emit placemarkDelegateChanged(placemarkDelegate); } void MarbleQuickItem::loadSettings() { QSettings settings; settings.beginGroup(QStringLiteral("MarbleQuickItem")); double lon = settings.value(QStringLiteral("centerLon"), QVariant(0.0)).toDouble(); double lat = settings.value(QStringLiteral("centerLat"), QVariant(0.0)).toDouble(); if (lat == 0.0 && lon == 0.0) { centerOnCurrentPosition(); } else { centerOn(lon, lat); } int const zoom = settings.value(QStringLiteral("zoom"), QVariant(0)).toInt(); if (zoom > 0) { setZoom(zoom); } settings.endGroup(); d->m_model.routingManager()->readSettings(); d->m_model.bookmarkManager()->loadFile(QStringLiteral("bookmarks/bookmarks.kml")); d->m_model.bookmarkManager()->setShowBookmarks(true); } void MarbleQuickItem::writeSettings() { QSettings settings; settings.beginGroup(QStringLiteral("MarbleQuickItem")); settings.setValue(QStringLiteral("centerLon"), QVariant(d->m_map.centerLongitude())); settings.setValue(QStringLiteral("centerLat"), QVariant(d->m_map.centerLatitude())); settings.setValue(QStringLiteral("zoom"), QVariant(zoom())); settings.endGroup(); d->m_model.routingManager()->writeSettings(); } void MarbleQuickItem::reloadTiles() { d->m_map.reload(); } void MarbleQuickItem::highlightRouteRelation(qint64 osmId, bool enabled) { d->m_map.highlightRouteRelation(osmId, enabled); } QObject *MarbleQuickItem::getEventFilter() const { //We would want to install the same event filter for abstract layer QuickItems such as PinchArea return &d->m_inputHandler; } void MarbleQuickItem::pinch(const QPointF& center, qreal scale, Qt::GestureState state) { d->m_inputHandler.pinch(center, scale, state); } MarbleInputHandler *MarbleQuickItem::inputHandler() { return &d->m_inputHandler; } int MarbleQuickItem::radius() const { return d->m_map.radius(); } int MarbleQuickItem::zoom() const { return d->m_presenter.logzoom(); } bool MarbleQuickItem::layersEventFilter(QObject *, QEvent *) { //Does nothing, but can be reimplemented in a subclass return false; } QuickItemSelectionRubber::QuickItemSelectionRubber() : m_visible(false) { // nothing to do } } diff --git a/src/lib/marble/declarative/Placemark.cpp b/src/lib/marble/declarative/Placemark.cpp index 185c6058c..b8aeb119e 100644 --- a/src/lib/marble/declarative/Placemark.cpp +++ b/src/lib/marble/declarative/Placemark.cpp @@ -1,739 +1,736 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2011 Dennis Nienhüser // #include "Placemark.h" #ifdef HAVE_QT5_POSITIONING #include #include #endif // HAVE_QT5_POSITIONING #include #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include "GeoDataTypes.h" #include "GeoDataDocument.h" namespace Marble { Placemark::Placemark(QObject *parent ) : QObject( parent ) { // nothing to do } void Placemark::setGeoDataPlacemark( const Marble::GeoDataPlacemark &placemark ) { m_placemark = placemark; m_address = QString(); m_description = QString(); m_website = QString(); m_wikipedia = QString(); m_openingHours = QString(); m_wheelchairInfo = QString(); m_wifiAvailable = QString(); updateTags(); updateRelations(placemark); emit coordinatesChanged(); emit nameChanged(); emit descriptionChanged(); emit addressChanged(); emit websiteChanged(); emit wikipediaChanged(); emit openingHoursChanged(); emit wheelchairInfoChanged(); emit wifiAvailabilityChanged(); emit tagsChanged(); } Marble::GeoDataPlacemark & Placemark::placemark() { return m_placemark; } const GeoDataPlacemark &Placemark::placemark() const { return m_placemark; } QString Placemark::name() const { return m_placemark.displayName(); } QString Placemark::description() const { if (m_description.isEmpty()) { auto const category = m_placemark.visualCategory(); m_description = m_placemark.categoryName(); if (category == GeoDataPlacemark::AccomodationHotel || category == GeoDataPlacemark::FoodRestaurant) { QString const stars = m_placemark.osmData().tagValue(QStringLiteral("stars")); if (!stars.isEmpty()) { bool hasStars; int const numStars = stars.mid(0, 1).toInt(&hasStars); if (hasStars) { m_description += QString(' ') + QString("★").repeated(numStars) + stars.mid(1); } else { addTagValue(m_description, QStringLiteral("stars")); } } addFirstTagValueOf(m_description, QStringList() << "brand" << "operator"); } if ((category >= GeoDataPlacemark::AccomodationHostel && category <= GeoDataPlacemark::AccomodationGuestHouse) || category == GeoDataPlacemark::HealthHospital) { int const rooms = m_placemark.osmData().tagValue(QStringLiteral("rooms")).toInt(); if (rooms > 0) { //~ singular %n room //~ plural %n rooms addTagValue(m_description, QStringLiteral("rooms"), tr("%n rooms", 0, rooms)); } int const beds = m_placemark.osmData().tagValue(QStringLiteral("beds")).toInt(); if (beds > 0) { //~ singular %n bed //~ plural %n beds addTagValue(m_description, QStringLiteral("beds"), tr("%n beds", 0, beds)); } } if (category == GeoDataPlacemark::TransportParking || category == GeoDataPlacemark::TransportBicycleParking || category == GeoDataPlacemark::TransportMotorcycleParking) { addTagValue(m_description, QStringLiteral("capacity"), tr("%1 parking spaces")); addTagValue(m_description, QStringLiteral("maxstay"), tr("Maximum parking time %1")); } if (category >= GeoDataPlacemark::FoodBar && category <= GeoDataPlacemark::FoodRestaurant) { if (category != GeoDataPlacemark::FoodRestaurant) { addFirstTagValueOf(m_description, QStringList() << "brand" << "operator"); } else { // Do nothing, already added in stars section above } addTagValue(m_description, "cuisine"); addTagValue(m_description, "brewery"); addTagDescription(m_description, "self_service", "yes", "Self Service"); addTagDescription(m_description, "takeaway", "yes", "Take Away"); addTagDescription(m_description, "outdoor_seating", "yes", "Outdoor Seating"); addTagDescription(m_description, "ice_cream", "yes", "Ice Cream"); addTagDescription(m_description, "smoking", "dedicated", "Smoking (dedicated)"); addTagDescription(m_description, "smoking", "yes", "Smoking allowed"); addTagDescription(m_description, "smoking", "separated", "Smoking (separated)"); addTagDescription(m_description, "smoking", "isolated", "Smoking (isolated)"); addTagDescription(m_description, "smoking", "no", "No smoking"); addTagDescription(m_description, "smoking", "outside", "Smoking (outside)"); addTagDescription(m_description, "smoking:outside", "yes", "Smoking (outside)"); addTagDescription(m_description, "smoking:outside", "separated", "Smoking (outside separated)"); addTagDescription(m_description, "smoking:outside", "no", "No smoking outside"); } else if (category >= GeoDataPlacemark::ShopBeverages && category <= GeoDataPlacemark::Shop) { addFirstTagValueOf(m_description, QStringList() << "brand" << "operator"); addTagValue(m_description, "clothes"); addTagValue(m_description, "designation"); if (category == GeoDataPlacemark::ShopButcher) { addTagValue(m_description, "butcher"); } else if (category == GeoDataPlacemark::ShopCopy) { addTagDescription(m_description, QStringLiteral("service:computer"), QStringLiteral("yes"), tr("Computers available", "A copy shop provides computers for customer use")); addTagDescription(m_description, QStringLiteral("service:computer"), QStringLiteral("no"), tr("No computers available", "A copy shop does not provide computers for customer use")); addTagDescription(m_description, QStringLiteral("service:copy"), QStringLiteral("yes"), tr("Photocopying service", "A copy shop provides photocopying service")); addTagDescription(m_description, QStringLiteral("service:copy"), QStringLiteral("no"), tr("No photocopying service", "A copy shop does not provide photocopying service")); addTagDescription(m_description, QStringLiteral("service:scan"), QStringLiteral("yes"), tr("Digital scanning", "A copy shop provides a service for scanning documents into digital files")); addTagDescription(m_description, QStringLiteral("service:scan"), QStringLiteral("no"), tr("No digital scanning", "A copy shop does not provide a service for scanning documents into digital files")); addTagDescription(m_description, QStringLiteral("service:fax"), QStringLiteral("yes"), tr("Fax service", "A copy shop provides a service to send documents through fax")); addTagDescription(m_description, QStringLiteral("service:fax"), QStringLiteral("no"), tr("No fax service", "A copy shop does not provide a service to send documents through fax")); addTagDescription(m_description, QStringLiteral("service:phone"), QStringLiteral("yes"), tr("Phone service", "A copy shop provides a paid service to make phone calls")); addTagDescription(m_description, QStringLiteral("service:phone"), QStringLiteral("no"), tr("No phone service", "A copy shop does not provide a paid service to make phone calls")); addTagDescription(m_description, QStringLiteral("service:print"), QStringLiteral("yes"), tr("Digital printing", "A copy shop provides services to print paper documents from digital files")); addTagDescription(m_description, QStringLiteral("service:print"), QStringLiteral("no"), tr("No digital printing", "A copy shop does not provide services to print paper documents from digital files")); addTagDescription(m_description, QStringLiteral("service:press"), QStringLiteral("yes"), tr("Press printing service", "A copy shop provides a professional service to print a large number of copies of a document")); addTagDescription(m_description, QStringLiteral("service:press"), QStringLiteral("no"), tr("No press printing service", "A copy shop does not provide a professional service to print a large number of copies of a document")); addTagDescription(m_description, QStringLiteral("service:prepress"), QStringLiteral("yes"), tr("Press printing assistance", "A copy shop provides help with preparing special printing techniques")); addTagDescription(m_description, QStringLiteral("service:prepress"), QStringLiteral("no"), tr("No press printing assistance", "A copy shop does not provide help with preparing special printing techniques")); addTagDescription(m_description, QStringLiteral("service:self"), QStringLiteral("yes"), tr("Self service", "A copy shop provides individual copy machines for self-service")); addTagDescription(m_description, QStringLiteral("service:self"), QStringLiteral("no"), tr(" No self service", "A copy shop does not provide individual machines for self-service")); } else if (category == GeoDataPlacemark::ShopDeli) { addTagDescription(m_description, QStringLiteral("organic"), QStringLiteral("yes"), tr("Sells organic food", "A deli that sells organic food")); addTagDescription(m_description, QStringLiteral("organic"), QStringLiteral("no"), tr("Does not sell organic food", "A deli that does not sell organic food")); addTagDescription(m_description, QStringLiteral("organic"), QStringLiteral("only"), tr("Only sells organic food", "A deli that only sells organic food")); addTagDescription(m_description, QStringLiteral("diet:gluten_free"), QStringLiteral("yes"), tr("Sells gluten free food", "A deli that sells gluten free food")); addTagDescription(m_description, QStringLiteral("diet:gluten_free"), QStringLiteral("no"), tr("Does not sell gluten free food", "A deli that does not sell gluten free food")); addTagDescription(m_description, QStringLiteral("diet:gluten_free"), QStringLiteral("only"), tr("Only sells gluten free food", "A deli that only sells gluten free food")); addTagDescription(m_description, QStringLiteral("diet:lactose_free"), QStringLiteral("yes"), tr("Sells lactose free food", "A deli that sells lactose free food")); addTagDescription(m_description, QStringLiteral("diet:lactose_free"), QStringLiteral("no"), tr("Does not sell lactose free food", "A deli that does not sell lactose free food")); addTagDescription(m_description, QStringLiteral("diet:lactose_free"), QStringLiteral("only"), tr("Only sells lactose free food", "A deli that only sells lactose free food")); } else if (category == GeoDataPlacemark::ShopTobacco) { addTagDescription(m_description, QStringLiteral("lottery"), QStringLiteral("yes"), tr("Sells lottery tickets", "A tobacco shop that also sells lottery tickets")); addTagDescription(m_description, QStringLiteral("stamps"), QStringLiteral("yes"), tr("Sells revenue stamps", "A tobacco shop that also sells revenue stamps")); addTagDescription(m_description, QStringLiteral("salt"), QStringLiteral("yes"), tr("Sells salt", "A tobacco shop that also sells salt")); } } else if (category == GeoDataPlacemark::TransportBusStop) { addTagValue(m_description, "network"); addTagValue(m_description, "operator"); addTagValue(m_description, "ref"); } else if (category == GeoDataPlacemark::TransportCarShare) { addTagValue(m_description, "network"); addTagValue(m_description, "operator"); } else if (category == GeoDataPlacemark::TransportRentalBicycle || category == GeoDataPlacemark::TransportRentalCar || category == GeoDataPlacemark::TransportRentalSki) { addFirstTagValueOf(m_description, QStringList() << "brand" << "operator"); } else if (category == GeoDataPlacemark::TransportFuel) { addFirstTagValueOf(m_description, QStringList() << "brand" << "operator"); addTagDescription(m_description, "fuel:diesel", "yes", tr("Diesel")); addTagDescription(m_description, "fuel:biodiesel", "yes", tr("Biodiesel")); addTagDescription(m_description, "fuel:octane_91", "yes", tr("Octane 91")); addTagDescription(m_description, "fuel:octane_95", "yes", tr("Octane 95")); addTagDescription(m_description, "fuel:octane_98", "yes", tr("Octane 98")); addTagDescription(m_description, "fuel:octane_100", "yes", tr("Octane 100")); addTagDescription(m_description, "fuel:e10", "yes", tr("E10")); addTagDescription(m_description, "fuel:lpg", "yes", tr("LPG")); } else if (category == GeoDataPlacemark::NaturalTree) { addTagValue(m_description, "species:en"); addTagValue(m_description, "genus:en"); addTagValue(m_description, "leaf_type"); } else if (category == GeoDataPlacemark::NaturalCave){ addTagValue(m_description, "cave:ref"); } else if (category == GeoDataPlacemark::AmenityRecycling) { addTagDescription(m_description, QStringLiteral("recycling:batteries"), "yes", tr("Batteries")); addTagDescription(m_description, QStringLiteral("recycling:clothes"), "yes", tr("Clothes")); addTagDescription(m_description, QStringLiteral("recycling:glass"), "yes", tr("Glass")); addTagDescription(m_description, QStringLiteral("recycling:glass_bottles"), "yes", tr("Glass bottles")); addTagDescription(m_description, QStringLiteral("recycling:green_waste"), "yes", tr("Green waste")); addTagDescription(m_description, QStringLiteral("recycling:garden_waste"), "yes", tr("Garden waste")); addTagDescription(m_description, QStringLiteral("recycling:electrical_items"), "yes", tr("Electrical items")); addTagDescription(m_description, QStringLiteral("recycling:metal"), "yes", tr("Metal")); addTagDescription(m_description, QStringLiteral("recycling:mobile_phones"), "yes", tr("Mobile phones")); addTagDescription(m_description, QStringLiteral("recycling:newspaper"), "yes", tr("Newspaper")); addTagDescription(m_description, QStringLiteral("recycling:paint"), "yes", tr("Paint")); addTagDescription(m_description, QStringLiteral("recycling:paper"), "yes", tr("Paper")); addTagDescription(m_description, QStringLiteral("recycling:paper_packaging"), "yes", tr("Paper packaging")); addTagDescription(m_description, QStringLiteral("recycling:PET"), "yes", tr("PET")); addTagDescription(m_description, QStringLiteral("recycling:plastic"), "yes", tr("Plastic")); addTagDescription(m_description, QStringLiteral("recycling:plastic_bags"), "yes", tr("Plastic bags")); addTagDescription(m_description, QStringLiteral("recycling:plastic_bottles"), "yes", tr("Plastic bottles")); addTagDescription(m_description, QStringLiteral("recycling:plastic_packaging"), "yes", tr("Plastic packaging")); addTagDescription(m_description, QStringLiteral("recycling:polyester"), "yes", tr("Polyester")); addTagDescription(m_description, QStringLiteral("recycling:tyres"), "yes", tr("Tyres")); addTagDescription(m_description, QStringLiteral("recycling:waste"), "yes", tr("Waste")); addTagDescription(m_description, QStringLiteral("recycling:white_goods"), "yes", tr("White goods")); addTagDescription(m_description, QStringLiteral("recycling:wood"), "yes", tr("Wood")); } else if (category == GeoDataPlacemark::NaturalVolcano) { addTagDescription(m_description, QStringLiteral("volcano:status"), QStringLiteral("active"), tr("Active", "An active volcano")); addTagDescription(m_description, QStringLiteral("volcano:status"), QStringLiteral("dormant"), tr("Dormant", "A dormant volcano that will erupt at some point in the future.")); addTagDescription(m_description, QStringLiteral("volcano:status"), QStringLiteral("extinct"), tr("Extinct", "A volcano considered extinct, it has not erupted within the last 10000 years and likely never will again.")); addTagDescription(m_description, QStringLiteral("volcano:type"), QStringLiteral("stratovolcano"), tr("Stratovolcano")); addTagDescription(m_description, QStringLiteral("volcano:type"), QStringLiteral("shield"), tr("Shield volcano")); addTagDescription(m_description, QStringLiteral("volcano:type"), QStringLiteral("scoria"), tr("Scoria cone", "A scoria cone volcano.")); } else if (category == GeoDataPlacemark::HealthDoctors) { addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("alternative"), tr("Alternative medicine")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("audiologist"), tr("Audiologist")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("blood_bank"), tr("Blood bank")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("blood_donation"), tr("Blood donation")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("centre"), tr("Medical center")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("clinic"), tr("Clinic")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("dentist"), tr("Dentist")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("doctor"), tr("Medical practitioner")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("hospital"), tr("Hospital")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("midwife"), tr("Midwife")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("optometrist"), tr("Optometrist")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("physiotherapist"), tr("Physiotherapist")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("podiatrist"), tr("Podiatrist")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("psychotherapist"), tr("Psychotherapist")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("rehabilitation"), tr("Rehabilitation")); addTagDescription(m_description, QStringLiteral("healthcare"), QStringLiteral("speech_therapist"), tr("Speech therapist")); addTagValue(m_description, QStringLiteral("healthcare:speciality")); } else if (category == GeoDataPlacemark::AmenityBench) { int const seats = m_placemark.osmData().tagValue(QStringLiteral("seats")).toInt(); if (seats > 0) { //~ singular %n seat //~ plural %n seats addTagValue(m_description, QStringLiteral("seats"), tr("%n seats", "number of seats a bench provides", seats)); } addTagValue(m_description, QStringLiteral("material")); addTagDescription(m_description, QStringLiteral("backrest"), QStringLiteral("yes"), tr("Has backrest", "A bench provides a backrest to lean against")); addTagDescription(m_description, QStringLiteral("backrest"), QStringLiteral("no"), tr("No backrest", "A bench provides no backrest to lean against")); } else if (category == GeoDataPlacemark::AmenityWasteBasket) { addTagValue(m_description, QStringLiteral("waste")); } else if (category == GeoDataPlacemark::TransportSpeedCamera) { addTagValue(m_description, QStringLiteral("maxspeed"), tr("%1 km/h")); addTagValue(m_description, "ref"); } else if (category == GeoDataPlacemark::TransportParking) { addTagDescription(m_description, QStringLiteral("supervised"), QStringLiteral("yes"), tr("Is supervised", "Parking spaces are supervised by guards")); addTagDescription(m_description, QStringLiteral("supervised"), QStringLiteral("no"), tr("Not supervised", "Parking spaces are not supervised by guards")); int const disabledSpaces = m_placemark.osmData().tagValue(QStringLiteral("capacity:disabled")).toInt(); if (disabledSpaces > 0) { addTagValue(m_description, QStringLiteral("capacity:disabled"), tr("%1 disabled spaces", "Parking spaces")); } int const womenSpaces = m_placemark.osmData().tagValue(QStringLiteral("capacity:women")).toInt(); if (womenSpaces > 0) { addTagValue(m_description, QStringLiteral("capacity:women"), tr("%1 women spaces", "Parking spaces")); } int const parentSpaces = m_placemark.osmData().tagValue(QStringLiteral("capacity:parent")).toInt(); if (parentSpaces > 0) { addTagValue(m_description, QStringLiteral("capacity:parent"), tr("%1 parent and child spaces", "Parking spaces")); } int const electricChargers = m_placemark.osmData().tagValue(QStringLiteral("capacity:charging")).toInt(); if (electricChargers > 0) { addTagValue(m_description, QStringLiteral("capacity:charging"), tr("%1 spaces with electric chargers", "Parking spaces")); } } else if (category == GeoDataPlacemark::TransportBicycleParking) { addTagDescription(m_description, QStringLiteral("surveillance"), QStringLiteral("outdoor"), tr("Has outdoor surveillance", "A parking space has outdoor surveillance")); addTagDescription(m_description, QStringLiteral("surveillance"), QStringLiteral("indoor"), tr("Has indoor surveillance", "A parking space has indoor surveillance")); addTagDescription(m_description, QStringLiteral("surveillance"), QStringLiteral("public"), tr("Has public surveillance", "A parking space has public surveillance")); } else if (category == GeoDataPlacemark::TourismWildernessHut) { addTagDescription(m_description, QStringLiteral("shower"), QStringLiteral("yes"), tr("Has shower", "A hut provides showers inside or aside")); addTagDescription(m_description, QStringLiteral("shower"), QStringLiteral("no"), tr("Has no shower", "A hut does not provide showers inside or aside")); addTagDescription(m_description, QStringLiteral("mattress"), QStringLiteral("yes"), tr("Has mattress", "A hut provides mattress")); addTagDescription(m_description, QStringLiteral("mattress"), QStringLiteral("no"), tr("Has no mattress", "A hut does not provide mattress")); addTagDescription(m_description, QStringLiteral("drinking_water"), QStringLiteral("yes"), tr("Has water", "Water is available inside or aside")); addTagDescription(m_description, QStringLiteral("drinking_water"), QStringLiteral("no"), tr("Has no water", "Water is not available inside nor aside")); addTagDescription(m_description, QStringLiteral("toilets"), QStringLiteral("yes"), tr("Has toilets", "A hut provides toilets")); addTagDescription(m_description, QStringLiteral("toilets"), QStringLiteral("no"), tr("Has no toilets", "A hut does not provide toilets")); addTagDescription(m_description, QStringLiteral("reservation"), QStringLiteral("yes"), tr("Reservation is possible")); addTagDescription(m_description, QStringLiteral("reservation"), QStringLiteral("no"), tr("No reservation possible")); addTagDescription(m_description, QStringLiteral("reservation"), QStringLiteral("required"), tr("Reservation is required")); addTagDescription(m_description, QStringLiteral("reservation"), QStringLiteral("recommended"), tr("Reservation is recommended", "You should make reservation")); addTagDescription(m_description, QStringLiteral("reservation"), QStringLiteral("members_only"), tr("Only for members", "Reservation is only possible for members of the organisation running the hut")); } else if (category == GeoDataPlacemark::TourismArtwork) { addTagValue(m_description, QStringLiteral("artist_name"), tr("By %1")); } else if (category == GeoDataPlacemark::AmenityChargingStation) { addTagValue(m_description, QStringLiteral("capacity"), tr("%1 vehicles")); addTagValue(m_description, QStringLiteral("amperage"), tr("%1 ampere")); addTagValue(m_description, QStringLiteral("voltage"), tr("%1 volt")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("cee_blue"), tr("%1 blue CEE sockets")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("cee_red_16a"), tr("%1 red CEE sockets (16 A)")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("cee_red_32a"), tr("%1 red CEE sockets (32 A)")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("cee_red_64a"), tr("%1 red CEE sockets (64 A)")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("cee_red_125a"), tr("%1 red CEE sockets (125 A)")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("nema_5_15"), tr("%1 NEMA-5-15P plugs")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("typeb"), tr("%1 NEMA-5-15P plugs")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("nema_5_20"), tr("%1 NEMA-5-20P plugs")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("nema_14_30"), tr("%1 NEMA 14-30 sockets")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("nema_14_50"), tr("%1 NEMA 14-50 sockets")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("schuko"), tr("%1 Schuko sockets")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("bs1363"), tr("%1 BS 1363 sockets")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("type1"), tr("%1 Type 1 plugs")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("type1_combo"), tr("%1 Type 1 combo plugs")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("type2"), tr("%1 Type 2 sockets")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("type2_combo"), tr("%1 Type 2 combo sockets")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("type3"), tr("%1 Type 3 sockets")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("chademo"), tr("%1 CHAdeMO plugs")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("magne_charge"), tr("%1 Magne Charge plugs")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("tesla_standard"), tr("%1 Tesla standard plugs")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("tesla_supercharger"), tr("%1 Tesla standard plugs (Supercharger)")); addTagDescription(m_description, QStringLiteral("socket"), QStringLiteral("tesla_roadster"), tr("%1 Tesla roadster plugs")); } else if (category == GeoDataPlacemark::AmenityCarWash) { addTagValue(m_description, QStringLiteral("maxwidth"), tr("Maximum vehicle width: %1")); addTagValue(m_description, QStringLiteral("maxheight"), tr("Maximum vehicle height: %1")); addTagDescription(m_description, QStringLiteral("self_service"), QStringLiteral("yes"), tr("Self-service")); addTagDescription(m_description, QStringLiteral("self_service"), QStringLiteral("no"), tr("No self-service")); addTagDescription(m_description, QStringLiteral("automated"), QStringLiteral("yes"), tr("Automated")); addTagDescription(m_description, QStringLiteral("automated"), QStringLiteral("no"), tr("Manual")); } else if (category == GeoDataPlacemark::AmenitySocialFacility) { addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("group_home"), tr("Group home")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("nursing_home"), tr("Nursing home")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("assisted_living"), tr("Assisted living", "Like group home but for more independent people, e.g. who have flats")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("day_care"), tr("Nursing services on a daily basis")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("shelter"), tr("Shelter")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("ambulatory_care"), tr("Ambulatory care")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("outreach"), tr("Social welfare services")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("workshop"), tr("Employment and workshops for offenders and people with disabilities")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("food_bank"), tr("Pre-packaged food for free or below market price")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("soup_kitchen"), tr("Prepared meals for free or below market price")); addTagDescription(m_description, QStringLiteral("social_facility"), QStringLiteral("dairy_kitchen"), tr("Free dairy food (subject to local regulations)")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("abused"), tr("For abused")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("child"), tr("For children")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("disabled"), tr("For people with physical disabilities")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("diseased"), tr("For those who suffer of a disease")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("drug_addicted"), tr("For drug-addicted")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("homeless"), tr("For homeless")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("juvenile"), tr("For juvenile")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("mental_health"), tr("For those with mental/psychological problems")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("migrant"), tr("For migrants")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("orphan"), tr("For orphans")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("senior"), tr("For elder people")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("underprivileged"), tr("For poor or disadvantaged people")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("unemployed"), tr("For unemployed")); addTagDescription(m_description, QStringLiteral("social_facility:for"), QStringLiteral("victim"), tr("For victims of crimes")); } else if (category == GeoDataPlacemark::HistoricMemorial) { addTagValue(m_description, QStringLiteral("inscription"), tr("Inscription: %1")); } else if (category >= GeoDataPlacemark::AerialwayCableCar && category <= GeoDataPlacemark::AerialwayGoods) { addTagValue(m_description, QStringLiteral("occupancy"), tr("%1 places per carriage")); addTagValue(m_description, QStringLiteral("capacity"), tr("%1 people per hour")); addTagValue(m_description, QStringLiteral("duration"), tr("%1 minutes")); addTagDescription(m_description, QStringLiteral("bubble"), QStringLiteral("yes"), tr("Has weather protection", "A carriage is protected from the weather")); addTagDescription(m_description, QStringLiteral("bubble"), QStringLiteral("no"), tr("No weather protection", "A carriage is not protected from the weather")); addTagDescription(m_description, QStringLiteral("heating"), QStringLiteral("yes"), tr("Is heated", "A carriage is heated")); addTagDescription(m_description, QStringLiteral("heating"), QStringLiteral("no"), tr("Not heated", "A carriage is not heated")); addTagDescription(m_description, QStringLiteral("bicycle"), QStringLiteral("yes"), tr("Bicycle transportation possible", "Bicycles can be transported")); addTagDescription(m_description, QStringLiteral("bicycle"), QStringLiteral("summer"), tr("Bicycle transportation only in summer", "Bicycles can only be transported in summer")); addTagDescription(m_description, QStringLiteral("bicycle"), QStringLiteral("no"), tr("Bicycle transportation impossible", "Bicyles cannot be transported")); } else if (category >= GeoDataPlacemark::PisteDownhill && category <= GeoDataPlacemark::PisteSkiJump) { addTagDescription(m_description, QStringLiteral("lit"), QStringLiteral("yes"), tr("Lit at night")); addTagDescription(m_description, QStringLiteral("piste:lit"), QStringLiteral("yes"), tr("Lit in winter")); addTagDescription(m_description, QStringLiteral("gladed"), QStringLiteral("yes"), tr("Contains trees", "A ski piste with trees (gladed)")); addTagDescription(m_description, QStringLiteral("patrolled"), QStringLiteral("no"), tr("Not patrolled")); addTagDescription(m_description, QStringLiteral("piste:grooming"), QStringLiteral("classic"), tr("Groomed for classic style nordic or downhill skiing")); addTagDescription(m_description, QStringLiteral("piste:grooming"), QStringLiteral("mogul"), tr("Mogul piste")); addTagDescription(m_description, QStringLiteral("piste:grooming"), QStringLiteral("skating"), tr("Groomed for free style or skating")); addTagDescription(m_description, QStringLiteral("piste:grooming"), QStringLiteral("classic;skating"), tr("Groomed for classic and free style skiing")); addTagDescription(m_description, QStringLiteral("piste:grooming"), QStringLiteral("classic+skating"), tr("Groomed for classic and free style skiing")); addTagDescription(m_description, QStringLiteral("piste:grooming"), QStringLiteral("scooter"), tr("Groomed by a smaller snowmobile")); addTagDescription(m_description, QStringLiteral("piste:grooming"), QStringLiteral("backcountry"), tr("Unmarked piste (backcountry touring)")); } if (category == GeoDataPlacemark::TransportBicycleParking || category == GeoDataPlacemark::TransportMotorcycleParking) { addTagDescription(m_description, QStringLiteral("covered"), QStringLiteral("yes"), tr("Is covered", "A parking space is covered")); addTagDescription(m_description, QStringLiteral("covered"), QStringLiteral("no"), tr("Not covered", "A parking space is not covered")); } if (category == GeoDataPlacemark::AmenityRecycling || category == GeoDataPlacemark::AmenityPostBox) { addTagValue(m_description, QStringLiteral("collection_times"), tr("Collection times %1"), QStringLiteral(", ")); } if (category == GeoDataPlacemark::AerialwayStation) { addTagDescription(m_description, "aerialway:access", "entry", tr("Entry", "Entry station of an aerialway")); addTagDescription(m_description, "aerialway:access", "exit", tr("Exit", "Exit station of an aerialway")); addTagDescription(m_description, "aerialway:access", "both", tr("Entry and exit", "Entry and exit station of an aerialway")); addTagDescription(m_description, "aerialway:access", "no", tr("No entry or exit", "Transit only station of an aerialway")); addTagDescription(m_description, "aerialway:summer:access", "entry", tr("Entry during summer", "Entry station of an aerialway during summer")); addTagDescription(m_description, "aerialway:summer:access", "exit", tr("Exit during summer", "Exit station of an aerialway during summer")); addTagDescription(m_description, "aerialway:summer:access", "both", tr("Entry and exit during summer", "Entry and exit station of an aerialway during summer")); addTagDescription(m_description, "aerialway:summer:access", "no", tr("No entry or exit during summer", "Transit only station of an aerialway during summer")); } if (category != GeoDataPlacemark::AerialwayStation) { addTagValue(m_description, QStringLiteral("ele"), tr("Elevation: %1 m")); } addTagDescription(m_description, "access", "customers", tr("Customers only")); addTagDescription(m_description, QStringLiteral("access"), QStringLiteral("yes"), tr("Accessible by anyone", "The public has an official, legally-enshrined right of access; i.e., it's a right of way")); addTagDescription(m_description, QStringLiteral("access"), QStringLiteral("private"), tr("Private", "Only with permission of the owner on an individual basis.")); addTagDescription(m_description, QStringLiteral("access"), QStringLiteral("permissive"), tr("Open to general traffic", "Open to general traffic but permission can be revoked by the owner")); addTagDescription(m_description, QStringLiteral("access"), QStringLiteral("no"), tr("No access", "No access for the general public")); addTagDescription(m_description, QStringLiteral("fee"), QStringLiteral("no"), tr("no fee")); addTagValue(m_description, QStringLiteral("description")); addTagValue(m_description, QStringLiteral("old_name"), tr("formerly %1")); const int level = m_placemark.osmData().tagValue(QStringLiteral("level")).toInt(); if (level > 2) { addTagValue(m_description, QStringLiteral("level"), tr("Floor %1", "Positive floor level")); } else if (level < -2) { addTagValue(m_description, QStringLiteral("level"), tr("Basement %1", "Negative floor level")); } else { addTagDescription(m_description, QStringLiteral("level"), QStringLiteral("2"), tr("Floor 2", "Floor level 2, two levels above ground level")); addTagDescription(m_description, QStringLiteral("level"), QStringLiteral("1"), tr("Floor 1", "Floor level 1, one level above ground level")); addTagDescription(m_description, QStringLiteral("level"), QStringLiteral("0"), tr("Ground floor", "Floor level 0")); addTagDescription(m_description, QStringLiteral("level"), QStringLiteral("-1"), tr("Basement 1", "Floor level -1, one level below ground level")); addTagDescription(m_description, QStringLiteral("level"), QStringLiteral("-2"), tr("Basement 2", "Floor level -2, two levels below ground level")); } } return m_description; } QString Placemark::address() const { if (m_address.isEmpty()) { m_address = addressFromOsmData(); } return m_address; } QString Placemark::website() const { if (!m_website.isEmpty()) { return m_website; } auto const tags = QStringList() << "website" << "contact:website" << "facebook" << "contact:facebook" << "url"; for(const QString &tag: tags) { QString const value = m_placemark.osmData().tagValue(tag); if (!value.isEmpty()) { QUrl url = QUrl(value); if (url.isValid()) { if (url.scheme().isEmpty()) { m_website = QStringLiteral("http://%1").arg(value); } else { m_website = value; } if (!m_website.isEmpty()) { return m_website; } } } } return m_website; } QString Placemark::wikipedia() const { if (!m_wikipedia.isEmpty()) { return m_wikipedia; } // TODO: also support "wikipedia:lang=page title" tags const QString wikipedia = m_placemark.osmData().tagValue("wikipedia"); if (!wikipedia.isEmpty()) { // full URL? if (wikipedia.startsWith(QLatin1String("http://")) || wikipedia.startsWith(QLatin1String("https://"))) { m_wikipedia = wikipedia; } else { // match "(lang:)human readable title" QRegularExpression re("^(?:([a-z]{2,}):)?(.*)$"); QRegularExpressionMatch match = re.match(wikipedia); QString lang = match.captured(1); if (lang.isEmpty()) { lang = QStringLiteral("en"); } const QString title = QString::fromLatin1(QUrl::toPercentEncoding(match.captured(2))); m_wikipedia = QLatin1String("https://") + lang + QLatin1String(".wikipedia.org/wiki/") + title; } } return m_wikipedia; } QString Placemark::openingHours() const { if (!m_openingHours.isEmpty()) { return m_openingHours; } addTagValue(m_openingHours, "opening_hours"); return m_openingHours; } QString Placemark::coordinates() const { return m_placemark.coordinate().toString(GeoDataCoordinates::Decimal).trimmed(); } QString Placemark::wheelchairInfo() const { if (!m_wheelchairInfo.isEmpty()) return m_wheelchairInfo; addTagDescription(m_wheelchairInfo, QStringLiteral("wheelchair"), QStringLiteral("yes"), tr("Wheelchair accessible")); addTagDescription(m_wheelchairInfo, QStringLiteral("wheelchair"), QStringLiteral("no"), tr("Wheelchair inaccessible")); addTagDescription(m_wheelchairInfo, QStringLiteral("wheelchair"), QStringLiteral("limited"), tr("Limited wheelchair accessibility")); addTagDescription(m_wheelchairInfo, QStringLiteral("wheelchair"), QStringLiteral("designated"), tr("Designated wheelchair access")); // Check if there is localized description auto const & osmData = m_placemark.osmData(); QStringList const uiLanguages = QLocale::system().uiLanguages(); const QString tag = QLatin1String("wheelchair:description:"); for (const QString &uiLanguage: uiLanguages) { for (auto tagIter = osmData.tagsBegin(), end = osmData.tagsEnd(); tagIter != end; ++tagIter) { if (tagIter.key().startsWith(tag)) { QStringRef const tagLanguage = tagIter.key().midRef(tag.length()); if (tagLanguage == uiLanguage) { append(m_wheelchairInfo, tagIter.value()); return m_wheelchairInfo; } } } } addTagValue(m_wheelchairInfo, "wheelchair:description"); return m_wheelchairInfo; } QString Placemark::wifiAvailable() const { if (!m_wifiAvailable.isEmpty()) { return m_wifiAvailable; } const auto& osmData = m_placemark.osmData(); addTagDescription(m_wifiAvailable, QStringLiteral("internet_access"), QStringLiteral("no"), tr("No public Internet access", "This location does not provide public Internet access")); addTagDescription(m_wifiAvailable, QStringLiteral("internet_access"), QStringLiteral("yes"), tr("Public Internet access available", "This location provides an unknown type of public Internet access.")); if (osmData.containsTag(QStringLiteral("internet_access:fee"), QStringLiteral("yes"))) { addTagDescription(m_wifiAvailable, QStringLiteral("internet_access"), QStringLiteral("wlan"), tr("Charged public wifi available", "Public wireless Internet access is available here for a fee.")); } else if (osmData.containsTag(QStringLiteral("internet_access:fee"), QStringLiteral("no"))) { addTagDescription(m_wifiAvailable, QStringLiteral("internet_access"), QStringLiteral("wlan"), tr("Free public wifi available", "Public wireless Internet access is available here for no cost.")); } else { addTagDescription(m_wifiAvailable, QStringLiteral("internet_access"), QStringLiteral("wlan"), tr("Public wifi available", "Public wireless Internet access is available here.")); } if (m_wifiAvailable.isEmpty()) { addTagDescription(m_wifiAvailable, QStringLiteral("wifi"), QStringLiteral("no"), tr("No public wifi", "Public wifi is not available here.")); addTagDescription(m_wifiAvailable, QStringLiteral("wifi"), QStringLiteral("yes"), tr("Public wifi available", "Public wireless Internet is available here.")); addTagDescription(m_wifiAvailable, QStringLiteral("wifi"), QStringLiteral("free"), tr("Free public wifi available", "Public wireless Internet is available here for no cost.")); } return m_wifiAvailable; } void Placemark::setName(const QString & name) { if (m_placemark.displayName() == name) { return; } m_placemark.setName(name); emit nameChanged(); } RouteRelationModel* Placemark::routeRelationModel() { return &m_relationModel; } double Placemark::longitude() const { return m_placemark.coordinate().longitude(GeoDataCoordinates::Degree); } double Placemark::latitude() const { return m_placemark.coordinate().latitude(GeoDataCoordinates::Degree); } const QStringList &Placemark::tags() const { return m_tags; } bool Placemark::addTagValue(QString &target, const QString &key, const QString &format, const QString separator) const { auto const & osmData = m_placemark.osmData(); QString const value = osmData.tagValue(key); if (!value.isEmpty()) { QString description = format.isEmpty() ? value : format.arg(value); description.replace(QLatin1Char(';'), separator); append(target, description); return true; } return false; } void Placemark::addFirstTagValueOf(QString &target, const QStringList &keys) const { for (auto const &key: keys) { if (addTagValue(target, key)) { return; } } } void Placemark::addTagDescription(QString &target, const QString &key, const QString &value, const QString &description) const { auto const & osmData = m_placemark.osmData(); if (osmData.containsTag(key, value)) { append(target, description); } } void Placemark::append(QString &target, const QString &value) const { if (!target.isEmpty()) { target += QStringLiteral(" · "); // non-latin1 } target += value; } QString Placemark::addressFromOsmData() const { #ifdef HAVE_QT5_POSITIONING QGeoAddress address; OsmPlacemarkData const data = m_placemark.osmData(); address.setCountry(data.tagValue("addr:country")); address.setState(data.tagValue("addr:state")); address.setCity(data.tagValue("addr:city")); address.setDistrict(data.tagValue("district")); address.setPostalCode(data.tagValue("addr:postcode")); QString const street = data.tagValue("addr:street"); QString const houseNumber = data.tagValue("addr:housenumber"); address.setStreet(formatStreet(street, houseNumber)); return address.text().replace("
", ", "); #else return QString(); #endif } QString Placemark::formatStreet(const QString &street, const QString &houseNumber) const { return houseNumber.isEmpty() ? street : tr("%1 %2", "House number (first argument) and street name (second argument) in an address").arg(houseNumber).arg(street).trimmed(); } void Placemark::updateTags() { m_tags.clear(); QString const tag = QStringLiteral("%1 = %2"); for (auto iter = m_placemark.osmData().tagsBegin(), end = m_placemark.osmData().tagsEnd(); iter != end; ++iter) { m_tags << tag.arg(iter.key()).arg(iter.value()); } } void Placemark::updateRelations(const Marble::GeoDataPlacemark &placemark) { - if (placemark.parent() && placemark.parent()->nodeType() == GeoDataTypes::GeoDataDocumentType) { + if (const auto document = (placemark.parent() ? geodata_cast(placemark.parent()) : 0)) { QVector allRelations; QSet relevantRelations; - auto const document = static_cast(placemark.parent()); QSet placemarkIds; auto const & osmData = placemark.osmData(); placemarkIds << osmData.oid(); bool searchRelations = true; for (auto feature: document->featureList()) { - if (feature->nodeType() == GeoDataTypes::GeoDataRelationType) { - auto relation = static_cast(feature); + if (const auto relation = geodata_cast(feature)) { allRelations << relation; if (relation->memberIds().contains(osmData.oid())) { relevantRelations << relation; auto const isRoute = relation->osmData().tagValue(QStringLiteral("type")) == QStringLiteral("route"); searchRelations &= !isRoute; } } } if (searchRelations) { for (auto feature: document->featureList()) { - if (feature->nodeType() == GeoDataTypes::GeoDataRelationType) { - auto relation = static_cast(feature); + if (const auto relation = geodata_cast(feature)) { if (relevantRelations.contains(relation) && relation->osmData().containsTag(QStringLiteral("type"), QStringLiteral("public_transport")) && relation->osmData().containsTag(QStringLiteral("public_transport"), QStringLiteral("stop_area"))) { for (auto iter = relation->osmData().relationReferencesBegin(), end = relation->osmData().relationReferencesEnd(); iter != end; ++iter) { if (iter.value() == QStringLiteral("stop") || iter.value() == QStringLiteral("platform")) { placemarkIds << iter.key(); } } } } } } for (auto relation: allRelations) { if (relation->containsAnyOf(placemarkIds)) { relevantRelations << relation; } } m_relationModel.setRelations(relevantRelations); } } } #include "moc_Placemark.cpp" diff --git a/src/lib/marble/geodata/data/GeoDataContainer.cpp b/src/lib/marble/geodata/data/GeoDataContainer.cpp index 6e23013e8..528eb6a9b 100644 --- a/src/lib/marble/geodata/data/GeoDataContainer.cpp +++ b/src/lib/marble/geodata/data/GeoDataContainer.cpp @@ -1,423 +1,421 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2007 Murad Tagirov // Copyright 2009 Patrick Spendrin // // Own #include "GeoDataContainer.h" #include "GeoDataContainer_p.h" // Marble #include "MarbleDebug.h" #include "GeoDataFeature.h" #include "GeoDataFolder.h" #include "GeoDataPlacemark.h" #include "GeoDataDocument.h" #include "GeoDataLatLonAltBox.h" #include "GeoDataGeometry.h" #include "GeoDataNetworkLinkControl.h" #include "GeoDataNetworkLink.h" #include "GeoDataGroundOverlay.h" #include "GeoDataPhotoOverlay.h" #include "GeoDataScreenOverlay.h" #include "GeoDataTour.h" #include namespace Marble { GeoDataContainer::GeoDataContainer() : GeoDataFeature( new GeoDataContainerPrivate ) { } GeoDataContainer::GeoDataContainer(GeoDataContainerPrivate *priv) : GeoDataFeature(priv) { Q_D(GeoDataContainer); d->setParent(this); } GeoDataContainer::GeoDataContainer(const GeoDataContainer& other, GeoDataContainerPrivate *priv) : GeoDataFeature(other, priv) { Q_D(GeoDataContainer); d->setParent(this); } GeoDataContainer::GeoDataContainer( const GeoDataContainer& other ) : GeoDataFeature(other, new GeoDataContainerPrivate(*other.d_func())) { Q_D(GeoDataContainer); d->setParent(this); } GeoDataContainer::~GeoDataContainer() { } GeoDataContainer& GeoDataContainer::operator=(const GeoDataContainer& other) { if (this != &other) { Q_D(GeoDataContainer); *d = *other.d_func(); } return *this; } bool GeoDataContainer::equals( const GeoDataContainer &other ) const { if ( !GeoDataFeature::equals(other) ) { return false; } Q_D(const GeoDataContainer); const GeoDataContainerPrivate* const other_d = other.d_func(); QVector::const_iterator thisBegin = d->m_vector.constBegin(); QVector::const_iterator thisEnd = d->m_vector.constEnd(); QVector::const_iterator otherBegin = other_d->m_vector.constBegin(); QVector::const_iterator otherEnd = other_d->m_vector.constEnd(); for (; thisBegin != thisEnd && otherBegin != otherEnd; ++thisBegin, ++otherBegin) { if (**thisBegin != **otherBegin) { return false; } } return thisBegin == thisEnd && otherBegin == otherEnd; } GeoDataLatLonAltBox GeoDataContainer::latLonAltBox() const { Q_D(const GeoDataContainer); GeoDataLatLonAltBox result; QVector::const_iterator it = d->m_vector.constBegin(); QVector::const_iterator end = d->m_vector.constEnd(); for (; it != end; ++it) { // Get all the placemarks from GeoDataContainer - if ( (*it)->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = static_cast(*it); - + if (const GeoDataPlacemark *placemark = geodata_cast(*it)) { // Only use visible placemarks for extracting their latLonAltBox and // making an union with the global latLonAltBox Marble will fit its // zoom to if (placemark->isVisible()) { if (result.isEmpty()) { result = placemark->geometry()->latLonAltBox(); } else { result |= placemark->geometry()->latLonAltBox(); } } } else if (const GeoDataContainer *container = dynamic_cast(*it)) { if (result.isEmpty()) { result = container->latLonAltBox(); } else { result |= container->latLonAltBox(); } } } return result; } QVector GeoDataContainer::folderList() const { Q_D(const GeoDataContainer); QVector results; QVector::const_iterator it = d->m_vector.constBegin(); QVector::const_iterator end = d->m_vector.constEnd(); for (; it != end; ++it) { GeoDataFolder *folder = dynamic_cast(*it); if ( folder ) { results.append( folder ); } } return results; } QVector GeoDataContainer::placemarkList() const { Q_D(const GeoDataContainer); QVector results; for (auto it = d->m_vector.constBegin(), end = d->m_vector.constEnd(); it != end; ++it) { - if ((*it)->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - results.append(static_cast(*it)); + if (GeoDataPlacemark *placemark = geodata_cast(*it)) { + results.append(placemark); } } return results; } QVector GeoDataContainer::featureList() const { Q_D(const GeoDataContainer); return d->m_vector; } /** * @brief returns the requested child item */ GeoDataFeature* GeoDataContainer::child( int i ) { Q_D(GeoDataContainer); return d->m_vector.at(i); } const GeoDataFeature* GeoDataContainer::child( int i ) const { Q_D(const GeoDataContainer); return d->m_vector.at(i); } /** * @brief returns the position of an item in the list */ int GeoDataContainer::childPosition( const GeoDataFeature* object ) const { Q_D(const GeoDataContainer); for (int i = 0; i < d->m_vector.size(); ++i) { if (d->m_vector.at(i) == object) { return i; } } return -1; } void GeoDataContainer::insert( GeoDataFeature *other, int index ) { insert( index, other ); } void GeoDataContainer::insert( int index, GeoDataFeature *feature ) { Q_D(GeoDataContainer); feature->setParent(this); d->m_vector.insert( index, feature ); } void GeoDataContainer::append( GeoDataFeature *other ) { Q_D(GeoDataContainer); other->setParent(this); d->m_vector.append( other ); } void GeoDataContainer::remove( int index ) { Q_D(GeoDataContainer); d->m_vector.remove( index ); } void GeoDataContainer::remove(int index, int count) { Q_D(GeoDataContainer); d->m_vector.remove( index, count ); } int GeoDataContainer::removeAll(GeoDataFeature *feature) { Q_D(GeoDataContainer); #if QT_VERSION >= 0x050400 return d->m_vector.removeAll(feature); #else int count = 0; QVector &vector = d->m_vector; QVector::iterator it = vector.begin(); while(it != vector.end()) { if (*it == feature) { it = vector.erase(it); ++count; } else { ++it; } } return count; #endif } void GeoDataContainer::removeAt(int index) { Q_D(GeoDataContainer); d->m_vector.removeAt( index ); } void GeoDataContainer::removeFirst() { Q_D(GeoDataContainer); d->m_vector.removeFirst(); } void GeoDataContainer::removeLast() { Q_D(GeoDataContainer); d->m_vector.removeLast(); } bool GeoDataContainer::removeOne( GeoDataFeature *feature ) { Q_D(GeoDataContainer); #if QT_VERSION >= 0x050400 return d->m_vector.removeOne( feature ); #else QVector &vector = d->m_vector; const int i = vector.indexOf(feature); if (i < 0) { return false; } vector.remove(i); return true; #endif } int GeoDataContainer::size() const { Q_D(const GeoDataContainer); return d->m_vector.size(); } GeoDataFeature& GeoDataContainer::at( int pos ) { Q_D(GeoDataContainer); return *(d->m_vector[pos]); } const GeoDataFeature& GeoDataContainer::at( int pos ) const { Q_D(const GeoDataContainer); return *(d->m_vector.at(pos)); } GeoDataFeature& GeoDataContainer::last() { Q_D(GeoDataContainer); return *(d->m_vector.last()); } const GeoDataFeature& GeoDataContainer::last() const { Q_D(const GeoDataContainer); return *(d->m_vector.last()); } GeoDataFeature& GeoDataContainer::first() { Q_D(GeoDataContainer); return *(d->m_vector.first()); } const GeoDataFeature& GeoDataContainer::first() const { Q_D(const GeoDataContainer); return *(d->m_vector.first()); } void GeoDataContainer::clear() { Q_D(GeoDataContainer); qDeleteAll(d->m_vector); d->m_vector.clear(); } QVector::Iterator GeoDataContainer::begin() { Q_D(GeoDataContainer); return d->m_vector.begin(); } QVector::Iterator GeoDataContainer::end() { Q_D(GeoDataContainer); return d->m_vector.end(); } QVector::ConstIterator GeoDataContainer::constBegin() const { Q_D(const GeoDataContainer); return d->m_vector.constBegin(); } QVector::ConstIterator GeoDataContainer::constEnd() const { Q_D(const GeoDataContainer); return d->m_vector.constEnd(); } void GeoDataContainer::pack( QDataStream& stream ) const { Q_D(const GeoDataContainer); GeoDataFeature::pack( stream ); stream << d->m_vector.count(); for (QVector::const_iterator iterator = d->m_vector.constBegin(); iterator != d->m_vector.constEnd(); ++iterator ) { const GeoDataFeature *feature = *iterator; stream << feature->featureId(); feature->pack( stream ); } } void GeoDataContainer::unpack( QDataStream& stream ) { Q_D(GeoDataContainer); GeoDataFeature::unpack( stream ); int count; stream >> count; for ( int i = 0; i < count; ++i ) { int featureId; stream >> featureId; switch( featureId ) { case GeoDataDocumentId: /* not usable!!!! */ break; case GeoDataFolderId: { GeoDataFolder *folder = new GeoDataFolder; folder->unpack( stream ); d->m_vector.append( folder ); } break; case GeoDataPlacemarkId: { GeoDataPlacemark *placemark = new GeoDataPlacemark; placemark->unpack( stream ); d->m_vector.append( placemark ); } break; case GeoDataNetworkLinkId: break; case GeoDataScreenOverlayId: break; case GeoDataGroundOverlayId: break; default: break; }; } } } diff --git a/src/lib/marble/geodata/data/GeoDataFeature.cpp b/src/lib/marble/geodata/data/GeoDataFeature.cpp index 08c981523..46b02301a 100644 --- a/src/lib/marble/geodata/data/GeoDataFeature.cpp +++ b/src/lib/marble/geodata/data/GeoDataFeature.cpp @@ -1,558 +1,557 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2007 Murad Tagirov // Copyright 2009 Patrick Spendrin // #include "GeoDataFeature.h" #include "GeoDataFeature_p.h" #include #include #include "MarbleDirs.h" #include "MarbleDebug.h" #include "GeoDataStyle.h" #include "GeoDataStyleMap.h" #include "GeoDataContainer.h" #include "GeoDataDocument.h" #include "GeoDataFolder.h" #include "GeoDataGroundOverlay.h" #include "GeoDataNetworkLink.h" #include "GeoDataNetworkLinkControl.h" #include "GeoDataPhotoOverlay.h" #include "GeoDataPlacemark.h" #include "GeoDataScreenOverlay.h" #include "GeoDataTour.h" #include "GeoDataRegion.h" #include "GeoDataCamera.h" namespace Marble { const QSharedPointer GeoDataFeaturePrivate::s_defaultStyle(new GeoDataStyle); GeoDataFeature::GeoDataFeature() : d_ptr(new GeoDataFeaturePrivate()) { } GeoDataFeature::GeoDataFeature( const GeoDataFeature& other ) : GeoDataObject(), d_ptr(new GeoDataFeaturePrivate(*other.d_ptr)) { } GeoDataFeature::GeoDataFeature( const QString& name ) : d_ptr(new GeoDataFeaturePrivate()) { d_ptr->m_name = name; } GeoDataFeature::GeoDataFeature(GeoDataFeaturePrivate *dd) : GeoDataObject(), d_ptr(dd) { } GeoDataFeature::GeoDataFeature(const GeoDataFeature& other, GeoDataFeaturePrivate *dd) : GeoDataObject(), d_ptr(dd) { Q_UNUSED(other); // TODO: some classes pass "other" on and thus get duplicated id, also in operator=. Align behaviour } GeoDataFeature::~GeoDataFeature() { delete d_ptr; } GeoDataFeature& GeoDataFeature::operator=( const GeoDataFeature& other ) { if (this != &other) { *d_ptr = *other.d_ptr; } return *this; } bool GeoDataFeature::operator==(const GeoDataFeature &other) const { if (nodeType() != other.nodeType()) { return false; } if (nodeType() == GeoDataTypes::GeoDataDocumentType) { const GeoDataDocument &thisDoc = static_cast(*this); const GeoDataDocument &otherDoc = static_cast(other); return thisDoc == otherDoc; } else if (nodeType() == GeoDataTypes::GeoDataFolderType) { const GeoDataFolder &thisFolder = static_cast(*this); const GeoDataFolder &otherFolder = static_cast(other); return thisFolder == otherFolder; } else if (nodeType() == GeoDataTypes::GeoDataGroundOverlayType) { const GeoDataGroundOverlay &thisGO = static_cast(*this); const GeoDataGroundOverlay &otherGO = static_cast(other); return thisGO == otherGO; } else if (nodeType() == GeoDataTypes::GeoDataNetworkLinkType) { const GeoDataNetworkLink &thisNetLink = static_cast(*this); const GeoDataNetworkLink &otherNetLink = static_cast(other); return thisNetLink == otherNetLink; } else if (nodeType() == GeoDataTypes::GeoDataNetworkLinkControlType) { const GeoDataNetworkLinkControl &thisNLC = static_cast(*this); const GeoDataNetworkLinkControl &otherNLC = static_cast(other); return thisNLC == otherNLC; } else if (nodeType() == GeoDataTypes::GeoDataPhotoOverlayType) { const GeoDataPhotoOverlay &thisPO = static_cast(*this); const GeoDataPhotoOverlay &otherPO = static_cast(other); return thisPO == otherPO; } else if (nodeType() == GeoDataTypes::GeoDataPlacemarkType) { const GeoDataPlacemark &thisPM = static_cast(*this); const GeoDataPlacemark &otherPM = static_cast(other); return thisPM == otherPM; } else if (nodeType() == GeoDataTypes::GeoDataScreenOverlayType) { const GeoDataScreenOverlay &thisSO = static_cast(*this); const GeoDataScreenOverlay &otherSO = static_cast(other); return thisSO == otherSO; } else if (nodeType() == GeoDataTypes::GeoDataTourType) { const GeoDataTour &thisTour = static_cast(*this); const GeoDataTour &otherTour = static_cast(other); return thisTour == otherTour; } return false; } bool GeoDataFeature::equals( const GeoDataFeature &other ) const { Q_D(const GeoDataFeature); const GeoDataFeaturePrivate* const other_d = other.d_func(); if (!GeoDataObject::equals(other) || d->m_name != other_d->m_name || d->m_styleUrl != other_d->m_styleUrl || d->m_popularity != other_d->m_popularity || d->m_zoomLevel != other_d->m_zoomLevel || d->m_visible != other_d->m_visible || d->m_role != other_d->m_role || d->m_extendedData != other_d->m_extendedData || *style() != *other.style()) { return false; } if ((!d->m_styleMap && other_d->m_styleMap) || (d->m_styleMap && !other_d->m_styleMap)) { return false; } if ((d->m_styleMap && other_d->m_styleMap) && (*d->m_styleMap != *other_d->m_styleMap)) { return false; } if ((!d->m_featureExtendedData && other_d->m_featureExtendedData && other_d->m_featureExtendedData->m_abstractView) || (d->m_featureExtendedData && d->m_featureExtendedData->m_abstractView && !other_d->m_featureExtendedData)) { return false; } if ((d->m_featureExtendedData && other_d->m_featureExtendedData) && (*d->m_featureExtendedData != *other_d->m_featureExtendedData)) { return false; } return true; } EnumFeatureId GeoDataFeature::featureId() const { Q_D(const GeoDataFeature); return d->featureId(); } QString GeoDataFeature::name() const { Q_D(const GeoDataFeature); return d->m_name; } void GeoDataFeature::setName( const QString &value ) { Q_D(GeoDataFeature); d->m_name = value; } GeoDataSnippet GeoDataFeature::snippet() const { Q_D(const GeoDataFeature); return d->featureExtendedData().m_snippet; } void GeoDataFeature::setSnippet( const GeoDataSnippet &snippet ) { Q_D(GeoDataFeature); d->featureExtendedData().m_snippet = snippet; } QString GeoDataFeature::address() const { Q_D(const GeoDataFeature); if (!d->m_featureExtendedData) { return QString(); } return d->featureExtendedData().m_address; } void GeoDataFeature::setAddress( const QString &value) { Q_D(GeoDataFeature); if (value.isEmpty() && !d->m_featureExtendedData) { return; // nothing to change } d->featureExtendedData().m_address = value; } QString GeoDataFeature::phoneNumber() const { Q_D(const GeoDataFeature); if (!d->m_featureExtendedData) { return QString(); } return d->featureExtendedData().m_phoneNumber; } void GeoDataFeature::setPhoneNumber( const QString &value) { Q_D(GeoDataFeature); if (value.isEmpty() && !d->m_featureExtendedData) { return; // nothing to change } d->featureExtendedData().m_phoneNumber = value; } QString GeoDataFeature::description() const { Q_D(const GeoDataFeature); if (!d->m_featureExtendedData) { return QString(); } return d->featureExtendedData().m_description; } void GeoDataFeature::setDescription( const QString &value) { Q_D(GeoDataFeature); if (value.isEmpty() && !d->m_featureExtendedData) { return; // nothing to change } d->featureExtendedData().m_description = value; } bool GeoDataFeature::descriptionIsCDATA() const { Q_D(const GeoDataFeature); if (!d->m_featureExtendedData) { return false; } return d->featureExtendedData().m_descriptionCDATA; } void GeoDataFeature::setDescriptionCDATA( bool cdata ) { Q_D(GeoDataFeature); d->featureExtendedData().m_descriptionCDATA = cdata; } const GeoDataAbstractView* GeoDataFeature::abstractView() const { Q_D(const GeoDataFeature); if (!d->m_featureExtendedData) { return nullptr; } return d->featureExtendedData().m_abstractView; } GeoDataAbstractView *GeoDataFeature::abstractView() { // FIXME: Calling detach() doesn't help at all because the m_abstractView // object isn't actually copied in the Private class as well. // detach(); Q_D(GeoDataFeature); return d->featureExtendedData().m_abstractView; } void GeoDataFeature::setAbstractView( GeoDataAbstractView *abstractView ) { Q_D(GeoDataFeature); if (abstractView == nullptr && !d->m_featureExtendedData) { return; // nothing to change } d->featureExtendedData().m_abstractView = abstractView; } QString GeoDataFeature::styleUrl() const { Q_D(const GeoDataFeature); return d->m_styleUrl; } void GeoDataFeature::setStyleUrl( const QString &value ) { Q_D(GeoDataFeature); d->m_styleUrl = value; if ( value.isEmpty() ) { d->m_style = GeoDataStyle::Ptr(); return; } QString styleUrl = value; styleUrl.remove(QLatin1Char('#')); GeoDataObject *object = parent(); bool found = false; while ( object && !found ) { - if( object->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - GeoDataDocument *doc = static_cast ( object ); + if (GeoDataDocument *doc = geodata_cast(object)) { GeoDataStyleMap &styleMap = doc->styleMap( styleUrl ); const QString normalStyleUrl = styleMap.value(QStringLiteral("normal")); if (!normalStyleUrl.isEmpty()) { styleUrl = normalStyleUrl; styleUrl.remove(QLatin1Char('#')); } // Not calling setStyle here because we don't want // re-parenting of the style d->m_style = doc->style( styleUrl ); found = true; } object = object->parent(); } } bool GeoDataFeature::isVisible() const { Q_D(const GeoDataFeature); return d->m_visible; } void GeoDataFeature::setVisible( bool value ) { Q_D(GeoDataFeature); d->m_visible = value; } bool GeoDataFeature::isGloballyVisible() const { Q_D(const GeoDataFeature); if ( parent() == 0 ) { return d->m_visible; } const GeoDataContainer *container = static_cast(parent()); return d->m_visible && container->isGloballyVisible(); } const GeoDataTimeSpan &GeoDataFeature::timeSpan() const { Q_D(const GeoDataFeature); return d->featureExtendedData().m_timeSpan; } GeoDataTimeSpan &GeoDataFeature::timeSpan() { Q_D(GeoDataFeature); return d->featureExtendedData().m_timeSpan; } void GeoDataFeature::setTimeSpan( const GeoDataTimeSpan &timeSpan ) { Q_D(GeoDataFeature); d->featureExtendedData().m_timeSpan = timeSpan; } const GeoDataTimeStamp &GeoDataFeature::timeStamp() const { Q_D(const GeoDataFeature); return d->featureExtendedData().m_timeStamp; } GeoDataTimeStamp &GeoDataFeature::timeStamp() { Q_D(GeoDataFeature); return d->featureExtendedData().m_timeStamp; } void GeoDataFeature::setTimeStamp( const GeoDataTimeStamp &timeStamp ) { Q_D(GeoDataFeature); d->featureExtendedData().m_timeStamp = timeStamp; } const GeoDataExtendedData &GeoDataFeature::extendedData() const { Q_D(const GeoDataFeature); return d->m_extendedData; } GeoDataStyle::ConstPtr GeoDataFeature::style() const { Q_D(const GeoDataFeature); if (d->m_style) { return d->m_style; } return GeoDataFeaturePrivate::s_defaultStyle; } GeoDataStyle::ConstPtr GeoDataFeature::customStyle() const { Q_D(const GeoDataFeature); return d->m_style; } void GeoDataFeature::setStyle( const GeoDataStyle::Ptr &style ) { Q_D(GeoDataFeature); if (style) style->setParent( this ); d->m_style = style; } GeoDataExtendedData& GeoDataFeature::extendedData() { Q_D(GeoDataFeature); return d->m_extendedData; } void GeoDataFeature::setExtendedData( const GeoDataExtendedData& extendedData ) { Q_D(GeoDataFeature); d->m_extendedData = extendedData; } const GeoDataRegion& GeoDataFeature::region() const { Q_D(const GeoDataFeature); return d->featureExtendedData().m_region; } GeoDataRegion& GeoDataFeature::region() { Q_D(GeoDataFeature); return d->featureExtendedData().m_region; } void GeoDataFeature::setRegion( const GeoDataRegion& region ) { Q_D(GeoDataFeature); d->featureExtendedData().m_region = region; } const QString GeoDataFeature::role() const { Q_D(const GeoDataFeature); return d->m_role; } void GeoDataFeature::setRole( const QString &role ) { Q_D(GeoDataFeature); d->m_role = role; } const GeoDataStyleMap* GeoDataFeature::styleMap() const { Q_D(const GeoDataFeature); return d->m_styleMap; } void GeoDataFeature::setStyleMap( const GeoDataStyleMap* styleMap ) { Q_D(GeoDataFeature); d->m_styleMap = styleMap; } int GeoDataFeature::zoomLevel() const { Q_D(const GeoDataFeature); return d->m_zoomLevel; } void GeoDataFeature::setZoomLevel( int zoomLevel ) { Q_D(GeoDataFeature); d->m_zoomLevel = zoomLevel; } qint64 GeoDataFeature::popularity() const { Q_D(const GeoDataFeature); return d->m_popularity; } void GeoDataFeature::setPopularity( qint64 popularity ) { Q_D(GeoDataFeature); d->m_popularity = popularity; } void GeoDataFeature::pack( QDataStream& stream ) const { Q_D(const GeoDataFeature); GeoDataObject::pack( stream ); stream << d->m_name; stream << d->featureExtendedData().m_address; stream << d->featureExtendedData().m_phoneNumber; stream << d->featureExtendedData().m_description; stream << d->m_visible; // stream << d->m_visualCategory; stream << d->m_role; stream << d->m_popularity; stream << d->m_zoomLevel; } void GeoDataFeature::unpack( QDataStream& stream ) { Q_D(GeoDataFeature); GeoDataObject::unpack( stream ); stream >> d->m_name; stream >> d->featureExtendedData().m_address; stream >> d->featureExtendedData().m_phoneNumber; stream >> d->featureExtendedData().m_description; stream >> d->m_visible; // stream >> (int)d->m_visualCategory; stream >> d->m_role; stream >> d->m_popularity; stream >> d->m_zoomLevel; } } diff --git a/src/lib/marble/geodata/data/GeoDataObject.h b/src/lib/marble/geodata/data/GeoDataObject.h index 648d3e7ed..1e4dce926 100644 --- a/src/lib/marble/geodata/data/GeoDataObject.h +++ b/src/lib/marble/geodata/data/GeoDataObject.h @@ -1,107 +1,150 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2007 Murad Tagirov // Copyright 2008 Jens-Michael Hoffmann // #ifndef MARBLE_GEODATAOBJECT_H #define MARBLE_GEODATAOBJECT_H #include "geodata_export.h" #include "GeoDocument.h" #include "Serializable.h" #include namespace Marble { class GeoDataObjectPrivate; /** * @short A base class for all geodata objects * * GeoDataObject is the base class for all geodata classes. It is * never instantiated by itself, but is always used as part of a * derived object. * * The Geodata objects are all modeled after the Google KML files as * defined in * http://code.google.com/apis/kml/documentation/kml_tags_21.html. * * A GeoDataObject contains 2 properties, both corresponding directly * to tags in the KML files: the id, which is a unique * identifier of the object, and a targetId which is used to * reference other objects that have already been loaded. * * The id property must only be set if the Update * mechanism of KML is used, which is currently not supported by * Marble. */ class GEODATA_EXPORT GeoDataObject : public GeoNode, public Serializable { public: GeoDataObject(); GeoDataObject( const GeoDataObject & ); GeoDataObject & operator=( const GeoDataObject & ); ~GeoDataObject() override; /// Provides the parent of the object in GeoDataContainers const GeoDataObject *parent() const; GeoDataObject *parent(); /// Sets the parent of the object void setParent(GeoDataObject *parent); /** * @brief Get the id of the object. */ QString id() const; /** * @brief Set the id of the object * @param value the new id value */ void setId( const QString &value ); /** * @brief Get the targetId of the object to be replaced */ QString targetId() const; /** * @brief set a new targetId of this object * @param value the new targetId value */ void setTargetId( const QString &value ); QString resolvePath( const QString &relativePath ) const; /// Reimplemented from Serializable void pack( QDataStream& stream ) const override; /// Reimplemented from Serializable void unpack( QDataStream& steam ) override; private: GeoDataObjectPrivate * d; protected: /** * @brief Compares the value of id and targetId of the two objects * @return true if they these values are equal or false otherwise */ virtual bool equals(const GeoDataObject &other) const; }; + +/** + * Returns the given node cast to type T if the node was instantiated as type T; otherwise returns 0. + * If node is 0 then it will also return 0. + * + * @param node pointer to GeoNode object to be casted + * @return the given node as type T if cast is successfull, otherwise 0 + */ +template +T *geodata_cast(GeoNode *node) +{ + if (node == nullptr) { + return nullptr; + } + + if (node->nodeType() == T().nodeType()) { + return static_cast(node); + } + + return nullptr; +} + +/** + * Returns the given node cast to type const T if the node was instantiated as type T; otherwise returns 0. + * If node is 0 then it will also return 0. + * + * @param node pointer to GeoNode object to be casted + * @return the given node as type const T if cast is successfull, otherwise 0 + */ +template +const T *geodata_cast(const GeoNode *node) +{ + if (node == nullptr) { + return nullptr; + } + + if (node->nodeType() == T().nodeType()) { + return static_cast(node); + } + + return nullptr; +} + } Q_DECLARE_METATYPE( Marble::GeoDataObject* ) #endif diff --git a/src/lib/marble/geodata/data/GeoDataPlacemark.cpp b/src/lib/marble/geodata/data/GeoDataPlacemark.cpp index e7cc1a83c..7c9630412 100644 --- a/src/lib/marble/geodata/data/GeoDataPlacemark.cpp +++ b/src/lib/marble/geodata/data/GeoDataPlacemark.cpp @@ -1,847 +1,843 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2004-2007 Torsten Rahn // Copyright 2007 Inge Wallin // Copyright 2008-2009 Patrick Spendrin // // Own #include "GeoDataPlacemark.h" // Private #include "GeoDataPlacemark_p.h" #include "GeoDataMultiGeometry.h" #include "GeoDataCoordinates.h" #include "GeoDataLatLonAltBox.h" #include "GeoDataData.h" #include "osm/OsmPlacemarkData.h" // Qt #include #include "MarbleDebug.h" #include "GeoDataTrack.h" #include "GeoDataModel.h" #include #include namespace Marble { const OsmPlacemarkData GeoDataPlacemarkPrivate::s_nullOsmPlacemarkData = OsmPlacemarkData(); const GeoDataPlacemarkExtendedData GeoDataPlacemarkPrivate::s_nullPlacemarkExtendedData = GeoDataPlacemarkExtendedData(); GeoDataPlacemark::GeoDataPlacemark() : GeoDataFeature( new GeoDataPlacemarkPrivate ) { Q_D(GeoDataPlacemark); d->m_geometry->setParent(this); } GeoDataPlacemark::GeoDataPlacemark( const GeoDataPlacemark& other ) : GeoDataFeature(other, new GeoDataPlacemarkPrivate(*other.d_func())) { Q_D(GeoDataPlacemark); if (d->m_geometry) { d->m_geometry->setParent(this); } } GeoDataPlacemark::GeoDataPlacemark( const QString& name ) : GeoDataFeature( new GeoDataPlacemarkPrivate ) { Q_D(GeoDataPlacemark); d->m_name = name; d->m_geometry->setParent(this); } GeoDataPlacemark::~GeoDataPlacemark() { // nothing to do } GeoDataPlacemark &GeoDataPlacemark::operator=( const GeoDataPlacemark &other ) { if (this != &other) { Q_D(GeoDataPlacemark); *d = *other.d_func(); if (d->m_geometry) { d->m_geometry->setParent(this); } } return *this; } bool GeoDataPlacemark::operator==( const GeoDataPlacemark& other ) const { Q_D(const GeoDataPlacemark); const GeoDataPlacemarkPrivate* const other_d = other.d_func(); if (!equals(other) || d->m_population != other_d->m_population) { return false; } if ((d->m_placemarkExtendedData && !other_d->m_placemarkExtendedData) && (*d->m_placemarkExtendedData != GeoDataPlacemarkExtendedData())) { return false; } if ((!d->m_placemarkExtendedData && other_d->m_placemarkExtendedData) && (GeoDataPlacemarkExtendedData() != *other_d->m_placemarkExtendedData)) { return false; } if (d->m_placemarkExtendedData && other_d->m_placemarkExtendedData && !(*d->m_placemarkExtendedData == *other_d->m_placemarkExtendedData)) { return false; } if (!d->m_geometry && !other_d->m_geometry) { return true; } if ((!d->m_geometry && other_d->m_geometry) || (d->m_geometry && !other_d->m_geometry)) { return false; } if (*d->m_geometry != *other_d->m_geometry) { return false; } return true; } bool GeoDataPlacemark::operator!=( const GeoDataPlacemark& other ) const { return !this->operator==( other ); } const char* GeoDataPlacemark::nodeType() const { return GeoDataTypes::GeoDataPlacemarkType; } GeoDataFeature * GeoDataPlacemark::clone() const { return new GeoDataPlacemark(*this); } GeoDataPlacemark::GeoDataVisualCategory GeoDataPlacemark::visualCategory() const { Q_D(const GeoDataPlacemark); return d->m_visualCategory; } void GeoDataPlacemark::setVisualCategory(GeoDataPlacemark::GeoDataVisualCategory index) { Q_D(GeoDataPlacemark); d->m_visualCategory = index; } GeoDataGeometry* GeoDataPlacemark::geometry() { Q_D(GeoDataPlacemark); return d->m_geometry; } const GeoDataGeometry* GeoDataPlacemark::geometry() const { Q_D(const GeoDataPlacemark); return d->m_geometry; } const OsmPlacemarkData& GeoDataPlacemark::osmData() const { Q_D(const GeoDataPlacemark); return d->osmPlacemarkData(); } void GeoDataPlacemark::setOsmData( const OsmPlacemarkData &osmData ) { Q_D(GeoDataPlacemark); d->osmPlacemarkData() = osmData; } OsmPlacemarkData& GeoDataPlacemark::osmData() { Q_D(GeoDataPlacemark); return d->osmPlacemarkData(); } bool GeoDataPlacemark::hasOsmData() const { Q_D(const GeoDataPlacemark); return d->m_osmPlacemarkData != nullptr; } void GeoDataPlacemark::clearOsmData() { Q_D(GeoDataPlacemark); delete d->m_osmPlacemarkData; d->m_osmPlacemarkData = nullptr; } const GeoDataLookAt *GeoDataPlacemark::lookAt() const { return dynamic_cast( abstractView() ); } GeoDataLookAt *GeoDataPlacemark::lookAt() { return dynamic_cast( abstractView() ); } bool GeoDataPlacemark::placemarkLayoutOrderCompare(const GeoDataPlacemark *left, const GeoDataPlacemark *right) { const GeoDataPlacemarkPrivate * const left_d = left->d_func(); const GeoDataPlacemarkPrivate * const right_d = right->d_func(); if (left_d->m_zoomLevel != right_d->m_zoomLevel) { return (left_d->m_zoomLevel < right_d->m_zoomLevel); // lower zoom level comes first } if (left_d->m_popularity != right_d->m_popularity) { return (left_d->m_popularity > right_d->m_popularity); // higher popularity comes first } return left < right; // lower pointer value comes first } GeoDataCoordinates GeoDataPlacemark::coordinate( const QDateTime &dateTime, bool *iconAtCoordinates ) const { Q_D(const GeoDataPlacemark); bool hasIcon = false; GeoDataCoordinates coord; if (d->m_geometry) { // Beware: comparison between pointers, not strings. - if (d->m_geometry->nodeType() == GeoDataTypes::GeoDataPointType - || d->m_geometry->nodeType() == GeoDataTypes::GeoDataPolygonType - || d->m_geometry->nodeType() == GeoDataTypes::GeoDataLinearRingType) { + if (geodata_cast(d->m_geometry) + || geodata_cast(d->m_geometry) + || geodata_cast(d->m_geometry)) { hasIcon = true; coord = d->m_geometry->latLonAltBox().center(); - } else if (d->m_geometry->nodeType() == GeoDataTypes::GeoDataMultiGeometryType) { - const GeoDataMultiGeometry *multiGeometry = static_cast(d->m_geometry); - + } else if (const auto multiGeometry = geodata_cast(d->m_geometry)) { QVector::ConstIterator it = multiGeometry->constBegin(); QVector::ConstIterator end = multiGeometry->constEnd(); for ( ; it != end; ++it ) { - if ((*it)->nodeType() == GeoDataTypes::GeoDataPointType - || (*it)->nodeType() == GeoDataTypes::GeoDataPolygonType - || (*it)->nodeType() == GeoDataTypes::GeoDataLinearRingType) { + if (geodata_cast(*it) + || geodata_cast(*it) + || geodata_cast(*it)) { hasIcon = true; break; } } coord = d->m_geometry->latLonAltBox().center(); - } else if (d->m_geometry->nodeType() == GeoDataTypes::GeoDataTrackType) { - const GeoDataTrack *track = static_cast(d->m_geometry); + } else if (const auto track = geodata_cast(d->m_geometry)) { hasIcon = track->size() != 0 && track->firstWhen() <= dateTime; coord = track->coordinatesAt( dateTime ); - } else if (d->m_geometry->nodeType() == GeoDataTypes::GeoDataLineStringType) { - GeoDataLineString const *lineString = static_cast(d->m_geometry); + } else if (const auto lineString = geodata_cast(d->m_geometry)) { auto const size = lineString->size(); if (size == 0) { return GeoDataCoordinates(); } else if (size < 3) { // Approximate center if there are just two coordinates return lineString->latLonAltBox().center(); } else { return lineString->at(size / 2); } } else { coord = d->m_geometry->latLonAltBox().center(); } } if ( iconAtCoordinates != 0 ) { *iconAtCoordinates = hasIcon; } return coord; } void GeoDataPlacemark::coordinate( qreal& lon, qreal& lat, qreal& alt ) const { coordinate().geoCoordinates( lon, lat, alt ); } void GeoDataPlacemark::setCoordinate( qreal lon, qreal lat, qreal alt, GeoDataPoint::Unit _unit) { setGeometry( new GeoDataPoint(lon, lat, alt, _unit ) ); } void GeoDataPlacemark::setCoordinate( const GeoDataCoordinates &point ) { setGeometry ( new GeoDataPoint( point ) ); } void GeoDataPlacemark::setGeometry( GeoDataGeometry *entry ) { Q_D(GeoDataPlacemark); delete d->m_geometry; d->m_geometry = entry; d->m_geometry->setParent(this); } QString GeoDataPlacemark::displayName() const { if (hasOsmData()) { OsmPlacemarkData const &data = osmData(); QStringList const uiLanguages = QLocale::system().uiLanguages(); for (const QString &uiLanguage: uiLanguages) { for (auto tagIter = data.tagsBegin(), end = data.tagsEnd(); tagIter != end; ++tagIter) { if (tagIter.key().startsWith(QLatin1String("name:"))) { QStringRef const tagLanguage = tagIter.key().midRef(5); if (tagLanguage == uiLanguage) { return tagIter.value(); } } } } } return name(); } QString GeoDataPlacemark::categoryName() const { Q_D(const GeoDataPlacemark); switch (d->m_visualCategory) { case Valley: return GeoDataPlacemarkPrivate::tr("Valley"); case OtherTerrain: return GeoDataPlacemarkPrivate::tr("Terrain"); case Crater: return GeoDataPlacemarkPrivate::tr("Crater"); case Mare: return GeoDataPlacemarkPrivate::tr("Sea"); case MannedLandingSite: return GeoDataPlacemarkPrivate::tr("Manned Landing Site"); case RoboticRover: return GeoDataPlacemarkPrivate::tr("Robotic Rover"); case UnmannedSoftLandingSite: return GeoDataPlacemarkPrivate::tr("Unmanned Soft Landing Site"); case UnmannedHardLandingSite: return GeoDataPlacemarkPrivate::tr("Unmanned Hard Landing Site"); case Mons: return GeoDataPlacemarkPrivate::tr("Mountain"); case SmallCity: return GeoDataPlacemarkPrivate::tr("City"); case SmallCountyCapital: return GeoDataPlacemarkPrivate::tr("County Capital"); case SmallStateCapital: return GeoDataPlacemarkPrivate::tr("State Capital"); case SmallNationCapital: return GeoDataPlacemarkPrivate::tr("Nation Capital"); case MediumCity: return GeoDataPlacemarkPrivate::tr("City"); case MediumCountyCapital: return GeoDataPlacemarkPrivate::tr("County Capital"); case MediumStateCapital: return GeoDataPlacemarkPrivate::tr("State Capital"); case MediumNationCapital: return GeoDataPlacemarkPrivate::tr("Nation Capital"); case BigCity: return GeoDataPlacemarkPrivate::tr("City"); case BigCountyCapital: return GeoDataPlacemarkPrivate::tr("County Capital"); case BigStateCapital: return GeoDataPlacemarkPrivate::tr("State Capital"); case BigNationCapital: return GeoDataPlacemarkPrivate::tr("Nation Capital"); case LargeCity: return GeoDataPlacemarkPrivate::tr("City"); case LargeCountyCapital: return GeoDataPlacemarkPrivate::tr("County Capital"); case LargeStateCapital: return GeoDataPlacemarkPrivate::tr("State Capital"); case LargeNationCapital: return GeoDataPlacemarkPrivate::tr("Nation Capital"); case Nation: return GeoDataPlacemarkPrivate::tr("Nation"); case Mountain: return GeoDataPlacemarkPrivate::tr("Mountain"); case Volcano: return GeoDataPlacemarkPrivate::tr("Volcano"); case Continent: return GeoDataPlacemarkPrivate::tr("Continent"); case Ocean: return GeoDataPlacemarkPrivate::tr("Ocean"); case GeographicPole: return GeoDataPlacemarkPrivate::tr("Geographic Pole"); case MagneticPole: return GeoDataPlacemarkPrivate::tr("Magnetic Pole"); case ShipWreck: return GeoDataPlacemarkPrivate::tr("Ship Wreck"); case AirPort: return GeoDataPlacemarkPrivate::tr("Air Port"); case Observatory: return GeoDataPlacemarkPrivate::tr("Observatory"); case MilitaryDangerArea: return GeoDataPlacemarkPrivate::tr("Military Danger Area"); case OsmSite: return GeoDataPlacemarkPrivate::tr("OSM Site"); case Coordinate: return GeoDataPlacemarkPrivate::tr("Coordinate"); case Bookmark: return GeoDataPlacemarkPrivate::tr("Bookmark"); case Satellite: return GeoDataPlacemarkPrivate::tr("Satellite"); // OpenStreetMap categories case PlaceCity: return GeoDataPlacemarkPrivate::tr("City"); case PlaceCityCapital: return GeoDataPlacemarkPrivate::tr("City Capital"); case PlaceCityNationalCapital: return GeoDataPlacemarkPrivate::tr("National Capital"); case PlaceSuburb: return GeoDataPlacemarkPrivate::tr("Suburb"); case PlaceHamlet: return GeoDataPlacemarkPrivate::tr("Hamlet"); case PlaceLocality: return GeoDataPlacemarkPrivate::tr("Locality"); case PlaceTown: return GeoDataPlacemarkPrivate::tr("Town"); case PlaceTownCapital: return GeoDataPlacemarkPrivate::tr("Town Capital"); case PlaceTownNationalCapital: return GeoDataPlacemarkPrivate::tr("National Capital"); case PlaceVillage: return GeoDataPlacemarkPrivate::tr("Village"); case PlaceVillageCapital: return GeoDataPlacemarkPrivate::tr("Village Capital"); case PlaceVillageNationalCapital: return GeoDataPlacemarkPrivate::tr("National Capital"); case NaturalWater: return GeoDataPlacemarkPrivate::tr("Water"); case NaturalReef: return GeoDataPlacemarkPrivate::tr("Reef"); case NaturalWood: return GeoDataPlacemarkPrivate::tr("Wood"); case NaturalBeach: return GeoDataPlacemarkPrivate::tr("Beach"); case NaturalWetland: return GeoDataPlacemarkPrivate::tr("Wetland"); case NaturalGlacier: return GeoDataPlacemarkPrivate::tr("Glacier"); case NaturalIceShelf: return GeoDataPlacemarkPrivate::tr("Ice Shelf"); case NaturalScrub: return GeoDataPlacemarkPrivate::tr("Scrub"); case NaturalCliff: return GeoDataPlacemarkPrivate::tr("Cliff"); case NaturalHeath: return GeoDataPlacemarkPrivate::tr("Heath"); case HighwayTrafficSignals: return GeoDataPlacemarkPrivate::tr("Traffic Signals"); case HighwaySteps: return GeoDataPlacemarkPrivate::tr("Steps"); case HighwayUnknown: return GeoDataPlacemarkPrivate::tr("Unknown Road"); case HighwayPath: return GeoDataPlacemarkPrivate::tr("Path"); case HighwayFootway: return GeoDataPlacemarkPrivate::tr("Footway"); case HighwayTrack: return GeoDataPlacemarkPrivate::tr("Track"); case HighwayPedestrian: return GeoDataPlacemarkPrivate::tr("Footway"); case HighwayCycleway: return GeoDataPlacemarkPrivate::tr("Cycleway"); case HighwayService: return GeoDataPlacemarkPrivate::tr("Service Road"); case HighwayRoad: return GeoDataPlacemarkPrivate::tr("Road"); case HighwayResidential: return GeoDataPlacemarkPrivate::tr("Residential Road"); case HighwayLivingStreet: return GeoDataPlacemarkPrivate::tr("Living Street"); case HighwayUnclassified: return GeoDataPlacemarkPrivate::tr("Unclassified Road"); case HighwayTertiaryLink: return GeoDataPlacemarkPrivate::tr("Tertiary Link Road"); case HighwayTertiary: return GeoDataPlacemarkPrivate::tr("Tertiary Road"); case HighwaySecondaryLink: return GeoDataPlacemarkPrivate::tr("Secondary Link Road"); case HighwaySecondary: return GeoDataPlacemarkPrivate::tr("Secondary Road"); case HighwayPrimaryLink: return GeoDataPlacemarkPrivate::tr("Primary Link Road"); case HighwayPrimary: return GeoDataPlacemarkPrivate::tr("Primary Road"); case HighwayRaceway: return GeoDataPlacemarkPrivate::tr("Raceway"); case HighwayTrunkLink: return GeoDataPlacemarkPrivate::tr("Trunk Link Road"); case HighwayTrunk: return GeoDataPlacemarkPrivate::tr("Trunk Road"); case HighwayMotorwayLink: return GeoDataPlacemarkPrivate::tr("Motorway Link Road"); case HighwayMotorway: return GeoDataPlacemarkPrivate::tr("Motorway"); case HighwayCorridor: return GeoDataPlacemarkPrivate::tr("Corridor"); case Building: return GeoDataPlacemarkPrivate::tr("Building"); case AccomodationCamping: return GeoDataPlacemarkPrivate::tr("Camping"); case AccomodationHostel: return GeoDataPlacemarkPrivate::tr("Hostel"); case AccomodationHotel: return GeoDataPlacemarkPrivate::tr("Hotel"); case AccomodationMotel: return GeoDataPlacemarkPrivate::tr("Motel"); case AccomodationYouthHostel: return GeoDataPlacemarkPrivate::tr("Youth Hostel"); case AccomodationGuestHouse: return GeoDataPlacemarkPrivate::tr("Guest House"); case AmenityLibrary: return GeoDataPlacemarkPrivate::tr("Library"); case AmenityKindergarten: return GeoDataPlacemarkPrivate::tr("Kindergarten"); case EducationCollege: return GeoDataPlacemarkPrivate::tr("College"); case EducationSchool: return GeoDataPlacemarkPrivate::tr("School"); case EducationUniversity: return GeoDataPlacemarkPrivate::tr("University"); case FoodBar: return GeoDataPlacemarkPrivate::tr("Bar"); case FoodBiergarten: return GeoDataPlacemarkPrivate::tr("Biergarten"); case FoodCafe: return GeoDataPlacemarkPrivate::tr("Cafe"); case FoodFastFood: return GeoDataPlacemarkPrivate::tr("Fast Food"); case FoodPub: return GeoDataPlacemarkPrivate::tr("Pub"); case FoodRestaurant: return GeoDataPlacemarkPrivate::tr("Restaurant"); case HealthDentist: return GeoDataPlacemarkPrivate::tr("Dentist"); case HealthDoctors: return GeoDataPlacemarkPrivate::tr("Doctors"); case HealthHospital: return GeoDataPlacemarkPrivate::tr("Hospital"); case HealthPharmacy: return GeoDataPlacemarkPrivate::tr("Pharmacy"); case HealthVeterinary: return GeoDataPlacemarkPrivate::tr("Veterinary"); case MoneyAtm: return GeoDataPlacemarkPrivate::tr("ATM"); case MoneyBank: return GeoDataPlacemarkPrivate::tr("Bank"); case HistoricArchaeologicalSite: return GeoDataPlacemarkPrivate::tr("Archaeological Site"); case AmenityEmbassy: return GeoDataPlacemarkPrivate::tr("Embassy"); case AmenityEmergencyPhone: return GeoDataPlacemarkPrivate::tr("Emergency Phone"); case AmenityMountainRescue: return GeoDataPlacemarkPrivate::tr("Mountain Rescue"); case LeisureWaterPark: return GeoDataPlacemarkPrivate::tr("Water Park"); case AmenityCommunityCentre: return GeoDataPlacemarkPrivate::tr("Community Centre"); case AmenityFountain: return GeoDataPlacemarkPrivate::tr("Fountain"); case AmenityNightClub: return GeoDataPlacemarkPrivate::tr("Night Club"); case AmenityBench: return GeoDataPlacemarkPrivate::tr("Bench"); case AmenityCourtHouse: return GeoDataPlacemarkPrivate::tr("Court House"); case AmenityFireStation: return GeoDataPlacemarkPrivate::tr("Fire Station"); case AmenityHuntingStand: return GeoDataPlacemarkPrivate::tr("Hunting Stand"); case AmenityPolice: return GeoDataPlacemarkPrivate::tr("Police"); case AmenityPostBox: return GeoDataPlacemarkPrivate::tr("Post Box"); case AmenityPostOffice: return GeoDataPlacemarkPrivate::tr("Post Office"); case AmenityPrison: return GeoDataPlacemarkPrivate::tr("Prison"); case AmenityRecycling: return GeoDataPlacemarkPrivate::tr("Recycling"); case AmenityShelter: return GeoDataPlacemarkPrivate::tr("Shelter"); case AmenityTelephone: return GeoDataPlacemarkPrivate::tr("Telephone"); case AmenityToilets: return GeoDataPlacemarkPrivate::tr("Toilets"); case AmenityTownHall: return GeoDataPlacemarkPrivate::tr("Town Hall"); case AmenityWasteBasket: return GeoDataPlacemarkPrivate::tr("Waste Basket"); case AmenityDrinkingWater: return GeoDataPlacemarkPrivate::tr("Drinking Water"); case AmenityGraveyard: return GeoDataPlacemarkPrivate::tr("Graveyard"); case AmenityChargingStation: return GeoDataPlacemarkPrivate::tr("Charging Station"); case AmenityCarWash: return GeoDataPlacemarkPrivate::tr("Car Wash"); case AmenitySocialFacility: return GeoDataPlacemarkPrivate::tr("Social Facility"); case BarrierCityWall: return GeoDataPlacemarkPrivate::tr("City Wall"); case BarrierGate: return GeoDataPlacemarkPrivate::tr("Gate"); case BarrierLiftGate: return GeoDataPlacemarkPrivate::tr("Lift Gate"); case BarrierWall: return GeoDataPlacemarkPrivate::tr("Wall"); case NaturalVolcano: return GeoDataPlacemarkPrivate::tr("Volcano"); case NaturalPeak: return GeoDataPlacemarkPrivate::tr("Peak"); case NaturalTree: return GeoDataPlacemarkPrivate::tr("Tree"); case NaturalCave: return GeoDataPlacemarkPrivate::tr("Cave Entrance"); case ShopBeverages: return GeoDataPlacemarkPrivate::tr("Beverages"); case ShopHifi: return GeoDataPlacemarkPrivate::tr("Hifi"); case ShopSupermarket: return GeoDataPlacemarkPrivate::tr("Supermarket"); case ShopAlcohol: return GeoDataPlacemarkPrivate::tr("Liquor Store"); case ShopBakery: return GeoDataPlacemarkPrivate::tr("Bakery"); case ShopButcher: return GeoDataPlacemarkPrivate::tr("Butcher"); case ShopConfectionery: return GeoDataPlacemarkPrivate::tr("Confectionery"); case ShopConvenience: return GeoDataPlacemarkPrivate::tr("Convenience Shop"); case ShopGreengrocer: return GeoDataPlacemarkPrivate::tr("Greengrocer"); case ShopSeafood: return GeoDataPlacemarkPrivate::tr("Seafood Shop"); case ShopDepartmentStore: return GeoDataPlacemarkPrivate::tr("Department Store"); case ShopKiosk: return GeoDataPlacemarkPrivate::tr("Kiosk"); case ShopBag: return GeoDataPlacemarkPrivate::tr("Bag Shop"); case ShopClothes: return GeoDataPlacemarkPrivate::tr("Clothes Shop"); case ShopFashion: return GeoDataPlacemarkPrivate::tr("Fashion Shop"); case ShopJewelry: return GeoDataPlacemarkPrivate::tr("Jewelry Shop"); case ShopShoes: return GeoDataPlacemarkPrivate::tr("Shoe Shop"); case ShopVarietyStore: return GeoDataPlacemarkPrivate::tr("Variety Store"); case ShopBeauty: return GeoDataPlacemarkPrivate::tr("Beauty Services"); case ShopChemist: return GeoDataPlacemarkPrivate::tr("Chemist"); case ShopCosmetics: return GeoDataPlacemarkPrivate::tr("Cosmetics"); case ShopHairdresser: return GeoDataPlacemarkPrivate::tr("Hairdresser"); case ShopOptician: return GeoDataPlacemarkPrivate::tr("Optician"); case ShopPerfumery: return GeoDataPlacemarkPrivate::tr("Perfumery"); case ShopDoitYourself: return GeoDataPlacemarkPrivate::tr("Hardware Store"); case ShopFlorist: return GeoDataPlacemarkPrivate::tr("Florist"); case ShopHardware: return GeoDataPlacemarkPrivate::tr("Hardware Store"); case ShopFurniture: return GeoDataPlacemarkPrivate::tr("Furniture Store"); case ShopElectronics: return GeoDataPlacemarkPrivate::tr("Electronics Shop"); case ShopMobilePhone: return GeoDataPlacemarkPrivate::tr("Mobile Phone Shop"); case ShopBicycle: return GeoDataPlacemarkPrivate::tr("Bicycle Shop"); case ShopCar: return GeoDataPlacemarkPrivate::tr("Car Dealer"); case ShopCarRepair: return GeoDataPlacemarkPrivate::tr("Car Repair Shop"); case ShopCarParts: return GeoDataPlacemarkPrivate::tr("Car Parts"); case ShopMotorcycle: return GeoDataPlacemarkPrivate::tr("Motorcycle Shop"); case ShopOutdoor: return GeoDataPlacemarkPrivate::tr("Outdoor Shop"); case ShopSports: return GeoDataPlacemarkPrivate::tr("Sports Shop"); case ShopCopy: return GeoDataPlacemarkPrivate::tr("Printing Services"); case ShopArt: return GeoDataPlacemarkPrivate::tr("Art Shop"); case ShopMusicalInstrument: return GeoDataPlacemarkPrivate::tr("Musical Instrument Shop"); case ShopPhoto: return GeoDataPlacemarkPrivate::tr("Photo Shop"); case ShopBook: return GeoDataPlacemarkPrivate::tr("Bookshop"); case ShopGift: return GeoDataPlacemarkPrivate::tr("Gift Shop"); case ShopStationery: return GeoDataPlacemarkPrivate::tr("Stationery"); case ShopLaundry: return GeoDataPlacemarkPrivate::tr("Laundry"); case ShopPet: return GeoDataPlacemarkPrivate::tr("Pet Shop"); case ShopToys: return GeoDataPlacemarkPrivate::tr("Toy Store"); case ShopTravelAgency: return GeoDataPlacemarkPrivate::tr("Travel Agency"); case ShopDeli: return GeoDataPlacemarkPrivate::tr("Deli"); case ShopTobacco: return GeoDataPlacemarkPrivate::tr("Tobacco Shop"); case ShopTea: return GeoDataPlacemarkPrivate::tr("Tea Shop"); case Shop: return GeoDataPlacemarkPrivate::tr("Shop"); case ManmadeBridge: return GeoDataPlacemarkPrivate::tr("Bridge"); case ManmadeLighthouse: return GeoDataPlacemarkPrivate::tr("Lighthouse"); case ManmadePier: return GeoDataPlacemarkPrivate::tr("Pier"); case ManmadeWaterTower: return GeoDataPlacemarkPrivate::tr("Water Tower"); case ManmadeWindMill: return GeoDataPlacemarkPrivate::tr("Wind Mill"); case TourismAttraction: return GeoDataPlacemarkPrivate::tr("Tourist Attraction"); case TourismArtwork: return GeoDataPlacemarkPrivate::tr("Artwork"); case HistoricCastle: return GeoDataPlacemarkPrivate::tr("Castle"); case AmenityCinema: return GeoDataPlacemarkPrivate::tr("Cinema"); case TourismInformation: return GeoDataPlacemarkPrivate::tr("Information"); case HistoricMonument: return GeoDataPlacemarkPrivate::tr("Monument"); case TourismMuseum: return GeoDataPlacemarkPrivate::tr("Museum"); case HistoricRuins: return GeoDataPlacemarkPrivate::tr("Ruin"); case AmenityTheatre: return GeoDataPlacemarkPrivate::tr("Theatre"); case TourismThemePark: return GeoDataPlacemarkPrivate::tr("Theme Park"); case TourismViewPoint: return GeoDataPlacemarkPrivate::tr("View Point"); case TourismZoo: return GeoDataPlacemarkPrivate::tr("Zoo"); case TourismAlpineHut: return GeoDataPlacemarkPrivate::tr("Alpine Hut"); case TourismWildernessHut: return GeoDataPlacemarkPrivate::tr("Wilderness Hut"); case HistoricMemorial: return GeoDataPlacemarkPrivate::tr("Memorial"); case TransportAerodrome: return GeoDataPlacemarkPrivate::tr("Aerodrome"); case TransportHelipad: return GeoDataPlacemarkPrivate::tr("Helipad"); case TransportAirportGate: return GeoDataPlacemarkPrivate::tr("Airport Gate"); case TransportAirportRunway: return GeoDataPlacemarkPrivate::tr("Airport Runway"); case TransportAirportApron: return GeoDataPlacemarkPrivate::tr("Airport Apron"); case TransportAirportTaxiway: return GeoDataPlacemarkPrivate::tr("Airport Taxiway"); case TransportAirportTerminal: return GeoDataPlacemarkPrivate::tr("Airport Terminal"); case TransportBusStation: return GeoDataPlacemarkPrivate::tr("Bus Station"); case TransportBusStop: return GeoDataPlacemarkPrivate::tr("Bus Stop"); case TransportCarShare: return GeoDataPlacemarkPrivate::tr("Car Sharing"); case TransportFuel: return GeoDataPlacemarkPrivate::tr("Gas Station"); case TransportParking: return GeoDataPlacemarkPrivate::tr("Parking"); case TransportParkingSpace: return GeoDataPlacemarkPrivate::tr("Parking Space"); case TransportPlatform: return GeoDataPlacemarkPrivate::tr("Platform"); case TransportRentalBicycle: return GeoDataPlacemarkPrivate::tr("Bicycle Rental"); case TransportRentalCar: return GeoDataPlacemarkPrivate::tr("Car Rental"); case TransportRentalSki: return GeoDataPlacemarkPrivate::tr("Ski Rental"); case TransportTaxiRank: return GeoDataPlacemarkPrivate::tr("Taxi Rank"); case TransportTrainStation: return GeoDataPlacemarkPrivate::tr("Train Station"); case TransportTramStop: return GeoDataPlacemarkPrivate::tr("Tram Stop"); case TransportBicycleParking: return GeoDataPlacemarkPrivate::tr("Bicycle Parking"); case TransportMotorcycleParking: return GeoDataPlacemarkPrivate::tr("Motorcycle Parking"); case TransportSubwayEntrance: return GeoDataPlacemarkPrivate::tr("Subway Entrance"); case TransportSpeedCamera: return GeoDataPlacemarkPrivate::tr("Speed Camera"); case ReligionPlaceOfWorship: return GeoDataPlacemarkPrivate::tr("Place Of Worship"); case ReligionBahai: return GeoDataPlacemarkPrivate::tr("Bahai"); case ReligionBuddhist: return GeoDataPlacemarkPrivate::tr("Buddhist"); case ReligionChristian: return GeoDataPlacemarkPrivate::tr("Christian"); case ReligionMuslim: return GeoDataPlacemarkPrivate::tr("Muslim"); case ReligionHindu: return GeoDataPlacemarkPrivate::tr("Hindu"); case ReligionJain: return GeoDataPlacemarkPrivate::tr("Jain"); case ReligionJewish: return GeoDataPlacemarkPrivate::tr("Jewish"); case ReligionShinto: return GeoDataPlacemarkPrivate::tr("Shinto"); case ReligionSikh: return GeoDataPlacemarkPrivate::tr("Sikh"); case LeisureGolfCourse: return GeoDataPlacemarkPrivate::tr("Golf Course"); case LeisureMarina: return GeoDataPlacemarkPrivate::tr("Marina"); case LeisurePark: return GeoDataPlacemarkPrivate::tr("Park"); case LeisurePlayground: return GeoDataPlacemarkPrivate::tr("Playground"); case LeisurePitch: return GeoDataPlacemarkPrivate::tr("Pitch"); case LeisureSportsCentre: return GeoDataPlacemarkPrivate::tr("Sports Centre"); case LeisureStadium: return GeoDataPlacemarkPrivate::tr("Stadium"); case LeisureTrack: return GeoDataPlacemarkPrivate::tr("Track"); case LeisureSwimmingPool: return GeoDataPlacemarkPrivate::tr("Swimming Pool"); case LeisureMinigolfCourse: return GeoDataPlacemarkPrivate::tr("Miniature Golf Course"); case LanduseAllotments: return GeoDataPlacemarkPrivate::tr("Allotments"); case LanduseBasin: return GeoDataPlacemarkPrivate::tr("Basin"); case LanduseCemetery: return GeoDataPlacemarkPrivate::tr("Cemetery"); case LanduseCommercial: return GeoDataPlacemarkPrivate::tr("Commercial"); case LanduseConstruction: return GeoDataPlacemarkPrivate::tr("Construction"); case LanduseFarmland: return GeoDataPlacemarkPrivate::tr("Farmland"); case LanduseFarmyard: return GeoDataPlacemarkPrivate::tr("Farmyard"); case LanduseGarages: return GeoDataPlacemarkPrivate::tr("Garages"); case LanduseGrass: return GeoDataPlacemarkPrivate::tr("Grass"); case LanduseIndustrial: return GeoDataPlacemarkPrivate::tr("Industrial"); case LanduseLandfill: return GeoDataPlacemarkPrivate::tr("Landfill"); case LanduseMeadow: return GeoDataPlacemarkPrivate::tr("Meadow"); case LanduseMilitary: return GeoDataPlacemarkPrivate::tr("Military"); case LanduseQuarry: return GeoDataPlacemarkPrivate::tr("Quarry"); case LanduseRailway: return GeoDataPlacemarkPrivate::tr("Railway"); case LanduseReservoir: return GeoDataPlacemarkPrivate::tr("Reservoir"); case LanduseResidential: return GeoDataPlacemarkPrivate::tr("Residential"); case LanduseRetail: return GeoDataPlacemarkPrivate::tr("Retail"); case LanduseOrchard: return GeoDataPlacemarkPrivate::tr("Orchard"); case LanduseVineyard: return GeoDataPlacemarkPrivate::tr("Vineyard"); case RailwayRail: return GeoDataPlacemarkPrivate::tr("Rail"); case RailwayNarrowGauge: return GeoDataPlacemarkPrivate::tr("Narrow Gauge"); case RailwayTram: return GeoDataPlacemarkPrivate::tr("Tram"); case RailwayLightRail: return GeoDataPlacemarkPrivate::tr("Light Rail"); case RailwayAbandoned: return GeoDataPlacemarkPrivate::tr("Abandoned Railway"); case RailwaySubway: return GeoDataPlacemarkPrivate::tr("Subway"); case RailwayPreserved: return GeoDataPlacemarkPrivate::tr("Preserved Railway"); case RailwayMiniature: return GeoDataPlacemarkPrivate::tr("Miniature Railway"); case RailwayConstruction: return GeoDataPlacemarkPrivate::tr("Railway Construction"); case RailwayMonorail: return GeoDataPlacemarkPrivate::tr("Monorail"); case RailwayFunicular: return GeoDataPlacemarkPrivate::tr("Funicular Railway"); case PowerTower: return GeoDataPlacemarkPrivate::tr("Power Tower"); case AerialwayStation: return GeoDataPlacemarkPrivate::tr("Aerialway Station"); case AerialwayPylon: return GeoDataPlacemarkPrivate::tr("Pylon", "A pylon supporting the aerialway cable e.g. on a ski lift"); case AerialwayCableCar: return GeoDataPlacemarkPrivate::tr("Cable Car"); case AerialwayGondola: return GeoDataPlacemarkPrivate::tr("Gondola"); case AerialwayChairLift: return GeoDataPlacemarkPrivate::tr("Chair Lift"); case AerialwayMixedLift: return GeoDataPlacemarkPrivate::tr("Mixed Lift"); case AerialwayDragLift: return GeoDataPlacemarkPrivate::tr("Drag Lift"); case AerialwayTBar: return GeoDataPlacemarkPrivate::tr("T-Bar"); case AerialwayJBar: return GeoDataPlacemarkPrivate::tr("J-Bar"); case AerialwayPlatter: return GeoDataPlacemarkPrivate::tr("Platter"); case AerialwayRopeTow: return GeoDataPlacemarkPrivate::tr("Rope Tow"); case AerialwayMagicCarpet: return GeoDataPlacemarkPrivate::tr("Magic Carpet"); case AerialwayZipLine: return GeoDataPlacemarkPrivate::tr("Zip Line"); case AerialwayGoods: return GeoDataPlacemarkPrivate::tr("Goods"); case PisteDownhill: return GeoDataPlacemarkPrivate::tr("Downhill Piste"); case PisteNordic: return GeoDataPlacemarkPrivate::tr("Nordic Piste"); case PisteSkitour: return GeoDataPlacemarkPrivate::tr("Skitour"); case PisteSled: return GeoDataPlacemarkPrivate::tr("Sled Piste"); case PisteHike: return GeoDataPlacemarkPrivate::tr("Winter Hike"); case PisteSleigh: return GeoDataPlacemarkPrivate::tr("Sleigh Piste"); case PisteIceSkate: return GeoDataPlacemarkPrivate::tr("Ice Skate"); case PisteSnowPark: return GeoDataPlacemarkPrivate::tr("Snow Park"); case PistePlayground: return GeoDataPlacemarkPrivate::tr("Ski Playground"); case PisteSkiJump: return GeoDataPlacemarkPrivate::tr("Ski Jump"); case AdminLevel1: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 1)"); case AdminLevel2: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 2)"); case AdminLevel3: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 3)"); case AdminLevel4: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 4)"); case AdminLevel5: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 5)"); case AdminLevel6: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 6)"); case AdminLevel7: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 7)"); case AdminLevel8: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 8)"); case AdminLevel9: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 9)"); case AdminLevel10: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 10)"); case AdminLevel11: return GeoDataPlacemarkPrivate::tr("Admin Boundary (Level 11)"); case BoundaryMaritime: return GeoDataPlacemarkPrivate::tr("Boundary (Maritime)"); case Landmass: return GeoDataPlacemarkPrivate::tr("Land Mass"); case UrbanArea: return GeoDataPlacemarkPrivate::tr("Urban Area"); case InternationalDateLine: return GeoDataPlacemarkPrivate::tr("International Date Line"); case Bathymetry: return GeoDataPlacemarkPrivate::tr("Bathymetry"); case WaterwayCanal: return GeoDataPlacemarkPrivate::tr("Canal"); case WaterwayDrain: return GeoDataPlacemarkPrivate::tr("Drain"); case WaterwayDitch: return GeoDataPlacemarkPrivate::tr("Ditch"); case WaterwayStream: return GeoDataPlacemarkPrivate::tr("Stream"); case WaterwayRiver: return GeoDataPlacemarkPrivate::tr("River"); case WaterwayWeir: return GeoDataPlacemarkPrivate::tr("Weir"); case CrossingSignals: return GeoDataPlacemarkPrivate::tr("Crosswalk"); case CrossingIsland: return GeoDataPlacemarkPrivate::tr("Crosswalk"); case CrossingZebra: return GeoDataPlacemarkPrivate::tr("Crosswalk"); case CrossingRailway: return GeoDataPlacemarkPrivate::tr("Railway Crossing"); case Default: case Unknown: case None: case LastIndex: return QString(); } return QString(); } qreal GeoDataPlacemark::area() const { Q_D(const GeoDataPlacemark); return d->m_placemarkExtendedData ? d->m_placemarkExtendedData->m_area : -1.0; } void GeoDataPlacemark::setArea( qreal area ) { if (area == -1.0 && !d_func()->m_placemarkExtendedData) { return; // nothing to do } Q_D(GeoDataPlacemark); d->placemarkExtendedData().m_area = area; } qint64 GeoDataPlacemark::population() const { Q_D(const GeoDataPlacemark); return d->m_population; } void GeoDataPlacemark::setPopulation( qint64 population ) { Q_D(GeoDataPlacemark); d->m_population = population; } const QString GeoDataPlacemark::state() const { Q_D(const GeoDataPlacemark); return d->m_placemarkExtendedData ? d->m_placemarkExtendedData->m_state : QString(); } void GeoDataPlacemark::setState( const QString &state ) { if (state.isEmpty() && !d_func()->m_placemarkExtendedData) { return; // nothing to do } Q_D(GeoDataPlacemark); d->placemarkExtendedData().m_state = state; } const QString GeoDataPlacemark::countryCode() const { Q_D(const GeoDataPlacemark); return d->m_placemarkExtendedData ? d->m_placemarkExtendedData->m_countrycode : QString(); } void GeoDataPlacemark::setCountryCode( const QString &countrycode ) { if (countrycode.isEmpty() && !d_func()->m_placemarkExtendedData) { return; // nothing to do } Q_D(GeoDataPlacemark); d->placemarkExtendedData().m_countrycode = countrycode; } bool GeoDataPlacemark::isBalloonVisible() const { Q_D(const GeoDataPlacemark); return d->m_placemarkExtendedData ? d->m_placemarkExtendedData->m_isBalloonVisible : false; } void GeoDataPlacemark::setBalloonVisible( bool visible ) { if (!visible && !d_func()->m_placemarkExtendedData) { return; // nothing to do } Q_D(GeoDataPlacemark); d->placemarkExtendedData().m_isBalloonVisible = visible; } void GeoDataPlacemark::pack( QDataStream& stream ) const { Q_D(const GeoDataPlacemark); GeoDataFeature::pack( stream ); stream << d->placemarkExtendedData().m_countrycode; stream << d->placemarkExtendedData().m_area; stream << d->m_population; if (d->m_geometry) { stream << d->m_geometry->geometryId(); d->m_geometry->pack( stream ); } else { stream << InvalidGeometryId; } } QXmlStreamWriter& GeoDataPlacemark::pack( QXmlStreamWriter& stream ) const { stream.writeStartElement( "placemark" ); stream.writeEndElement(); return stream; } QXmlStreamWriter& GeoDataPlacemark::operator <<( QXmlStreamWriter& stream ) const { pack( stream ); return stream; } void GeoDataPlacemark::unpack( QDataStream& stream ) { Q_D(GeoDataPlacemark); GeoDataFeature::unpack( stream ); stream >> d->placemarkExtendedData().m_countrycode; stream >> d->placemarkExtendedData().m_area; stream >> d->m_population; int geometryId; stream >> geometryId; GeoDataGeometry *geometry = nullptr; switch( geometryId ) { case InvalidGeometryId: break; case GeoDataPointId: { GeoDataPoint* point = new GeoDataPoint; point->unpack( stream ); geometry = point; } break; case GeoDataLineStringId: { GeoDataLineString* lineString = new GeoDataLineString; lineString->unpack( stream ); geometry = lineString; } break; case GeoDataLinearRingId: { GeoDataLinearRing* linearRing = new GeoDataLinearRing; linearRing->unpack( stream ); geometry = linearRing; } break; case GeoDataPolygonId: { GeoDataPolygon* polygon = new GeoDataPolygon; polygon->unpack( stream ); geometry = polygon; } break; case GeoDataMultiGeometryId: { GeoDataMultiGeometry* multiGeometry = new GeoDataMultiGeometry; multiGeometry->unpack( stream ); geometry = multiGeometry; } break; case GeoDataModelId: break; default: break; }; if (geometry) { delete d->m_geometry; d->m_geometry = geometry; d->m_geometry->setParent(this); } } } diff --git a/src/lib/marble/geodata/data/GeoDataRegion.cpp b/src/lib/marble/geodata/data/GeoDataRegion.cpp index 20bd25a13..d4b3da19e 100644 --- a/src/lib/marble/geodata/data/GeoDataRegion.cpp +++ b/src/lib/marble/geodata/data/GeoDataRegion.cpp @@ -1,168 +1,166 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2009 Torsten Rahn // // Own #include "GeoDataRegion.h" // Private #include "GeoDataRegion_p.h" // GeoData #include "GeoDataFeature.h" #include "GeoDataPlacemark.h" #include "GeoDataGeometry.h" #include "GeoDataTypes.h" // std #include namespace Marble { GeoDataRegion::GeoDataRegion() : GeoDataObject(), d( new GeoDataRegionPrivate ) { } GeoDataRegion::GeoDataRegion( const GeoDataRegion& other ) : GeoDataObject( other ), d( new GeoDataRegionPrivate( *other.d ) ) { } GeoDataRegion::GeoDataRegion( GeoDataFeature * feature ) : GeoDataObject(), d( new GeoDataRegionPrivate( feature ) ) { } GeoDataRegion::~GeoDataRegion() { delete d; } const char* GeoDataRegion::nodeType() const { return d->nodeType(); } bool GeoDataRegion::operator==(const GeoDataRegion& other) const { return equals(other) && this->latLonAltBox() == other.latLonAltBox() && this->lod() == other.lod(); } bool GeoDataRegion::operator!=(const GeoDataRegion& other) const { return !this->operator==(other); } const GeoDataLatLonAltBox& GeoDataRegion::latLonAltBox() const { // FIXME: This isn't exactly what a 'const' function should do, is it? // If the latLonAltBox hasn't been set try to determine it automatically if ( !d->m_latLonAltBox ) { // If there is a parent try to if ( d->m_parent ) { - if ( d->m_parent->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - - GeoDataPlacemark * placemark = dynamic_cast( d->m_parent ); + if (const GeoDataPlacemark *placemark = geodata_cast(d->m_parent)) { const GeoDataGeometry * geometry = placemark->geometry(); if ( geometry ) { d->m_latLonAltBox = new GeoDataLatLonAltBox( placemark->geometry()->latLonAltBox() ); } else { d->m_latLonAltBox = new GeoDataLatLonAltBox(); } } else { // If the parent is not a placemark then create a default LatLonAltBox // FIXME: reference a shared object instead d->m_latLonAltBox = new GeoDataLatLonAltBox(); } } else { // If there is no parent then create a default LatLonAltBox // FIXME: reference a shared object instead d->m_latLonAltBox = new GeoDataLatLonAltBox(); } } return *(d->m_latLonAltBox); } void GeoDataRegion::setLatLonAltBox( const GeoDataLatLonAltBox & latLonAltBox ) { delete d->m_latLonAltBox; d->m_latLonAltBox = new GeoDataLatLonAltBox( latLonAltBox ); } GeoDataLod& GeoDataRegion::lod() const { // If the lod hasn't been set then return a shared one if ( !d->m_lod ) { // FIXME: reference a shared object instead d->m_lod = new GeoDataLod(); } return *(d->m_lod); } void GeoDataRegion::setLod( const GeoDataLod & lod ) { delete d->m_lod; d->m_lod = new GeoDataLod( lod ); } void GeoDataRegion::pack( QDataStream& stream ) const { GeoDataObject::pack( stream ); d->m_lod->pack( stream ); d->m_latLonAltBox->pack( stream ); } void GeoDataRegion::unpack( QDataStream& stream ) { GeoDataObject::unpack( stream ); d->m_lod->unpack( stream ); d->m_latLonAltBox->unpack( stream ); } GeoDataRegion &GeoDataRegion::operator=( const GeoDataRegion& other ) { // Self assignment if ( this == &other ) return *this; GeoDataRegion temp( other ); swap( temp ); return *this; } void GeoDataRegion::swap( GeoDataRegion & other ) { std::swap( d, other.d ); } } diff --git a/src/lib/marble/geodata/handlers/kml/KmlMemberTagHandler.cpp b/src/lib/marble/geodata/handlers/kml/KmlMemberTagHandler.cpp index 87f6bae15..7c56bd637 100644 --- a/src/lib/marble/geodata/handlers/kml/KmlMemberTagHandler.cpp +++ b/src/lib/marble/geodata/handlers/kml/KmlMemberTagHandler.cpp @@ -1,67 +1,67 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Marius-Valeriu Stanciu // #include "KmlMemberTagHandler.h" #include "GeoDataPlacemark.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" #include "GeoDataGeometry.h" #include "GeoDataTypes.h" #include "KmlElementDictionary.h" #include "osm/OsmPlacemarkData.h" #include "GeoParser.h" #include namespace Marble { namespace kml { KML_DEFINE_TAG_HANDLER_MX( member ) GeoNode* KmlmemberTagHandler::parse( GeoParser& parser ) const { int memberIndex = parser.attribute( "index" ).toInt(); /* Only possible case: member of polygon placemark: *... * * * * * * ... * ... * ... */ if( parser.parentElement( 2 ).is() ) { GeoDataPlacemark *placemark = parser.parentElement( 2 ).nodeAs(); - if ( placemark->geometry()->nodeType() != GeoDataTypes::GeoDataPolygonType ) { + GeoDataPolygon *polygon = geodata_cast(placemark->geometry()); + if (polygon) { return 0; } - GeoDataPolygon *polygon = static_cast( placemark->geometry() ); // The memberIndex is used to determine which member this tag represents if ( memberIndex == -1 ) { return &polygon->outerBoundary(); } else { if ( memberIndex >= polygon->innerBoundaries().size() ) { return 0; } return &polygon->innerBoundaries()[ memberIndex ]; } } return 0; } } } diff --git a/src/lib/marble/geodata/handlers/kml/KmlNdTagHandler.cpp b/src/lib/marble/geodata/handlers/kml/KmlNdTagHandler.cpp index f3318045a..d9f3141d3 100644 --- a/src/lib/marble/geodata/handlers/kml/KmlNdTagHandler.cpp +++ b/src/lib/marble/geodata/handlers/kml/KmlNdTagHandler.cpp @@ -1,79 +1,76 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Marius-Valeriu Stanciu // // Self #include "KmlNdTagHandler.h" // Marble #include "KmlElementDictionary.h" #include "GeoDataExtendedData.h" #include "GeoDataGeometry.h" #include "GeoDataPlacemark.h" #include "GeoDataLineString.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" #include "GeoDataPoint.h" -#include "GeoDataTypes.h" #include "osm/OsmPlacemarkData.h" // Qt #include namespace Marble { namespace kml { KML_DEFINE_TAG_HANDLER_MX( nd ) GeoNode* KmlndTagHandler::parse( GeoParser& parser ) const { int ndIndex = parser.attribute( "index" ).toInt(); /* Case 1: node of a line placemark: *... * * * * ... * ... * ... */ if( parser.parentElement().represents( kmlTag_OsmPlacemarkData ) && parser.parentElement( 2 ).is() ) { GeoDataPlacemark *placemark = parser.parentElement( 2 ).nodeAs(); - if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { - GeoDataLineString *lineString = static_cast( placemark->geometry() ); - + if (auto lineString = geodata_cast(placemark->geometry())) { // Using GeoDataPoint because GeoDataCoordinates is not a GeoNode, so it can't be returned. GeoDataPoint *point = new GeoDataPoint( lineString->at( ndIndex ) ); return point; } return 0; } /* Case 2: node of a polygon's boundary *... * * * * * * ... * ... * ... */ else if ( parser.parentElement().represents( kmlTag_OsmPlacemarkData ) && parser.parentElement( 1 ).is() ) { GeoDataLinearRing *linearRing = parser.parentElement( 1 ).nodeAs(); // Using GeoDataPoint because GeoDataCoordinates is not a GeoNode, so it can't be returned. GeoDataPoint *point = new GeoDataPoint( linearRing->at( ndIndex ) ); return point; } return 0; } } } diff --git a/src/lib/marble/geodata/handlers/kml/KmlOsmPlacemarkDataTagHandler.cpp b/src/lib/marble/geodata/handlers/kml/KmlOsmPlacemarkDataTagHandler.cpp index 633a29e93..83b7e6b24 100644 --- a/src/lib/marble/geodata/handlers/kml/KmlOsmPlacemarkDataTagHandler.cpp +++ b/src/lib/marble/geodata/handlers/kml/KmlOsmPlacemarkDataTagHandler.cpp @@ -1,96 +1,95 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Marius-Valeriu Stanciu // // Marble #include "KmlOsmPlacemarkDataTagHandler.h" #include "KmlElementDictionary.h" #include "GeoDataExtendedData.h" #include "GeoDataGeometry.h" #include "GeoDataPlacemark.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" #include "GeoDataData.h" #include "GeoParser.h" -#include "GeoDataTypes.h" #include "GeoDataPoint.h" #include "osm/OsmPlacemarkData.h" #include namespace Marble { namespace kml { KML_DEFINE_TAG_HANDLER_MX( OsmPlacemarkData ) GeoNode* KmlOsmPlacemarkDataTagHandler::parse( GeoParser& parser ) const { OsmPlacemarkData osmData = OsmPlacemarkData::fromParserAttributes( parser.attributes() ); /* Case 1: This is the main OsmPlacemarkData of a placemark: * * * * ... */ if (parser.parentElement().is() && parser.parentElement(1).is()) { auto placemark = parser.parentElement(1).nodeAs(); placemark->setOsmData(osmData); return &placemark->osmData(); } /* Case 2: This is the OsmPlacemarkData of a Nd * * * * * * ... */ else if ( parser.parentElement( 1 ).is() && parser.parentElement().is() ) { OsmPlacemarkData* placemarkOsmData = parser.parentElement( 1 ).nodeAs(); GeoDataPoint *point = parser.parentElement().nodeAs(); GeoDataCoordinates coordinates = point->coordinates(); /* The GeoDataPoint object was only used as GeoNode wrapper for the GeoDataCoordinates * and it is no longer needed */ delete point; placemarkOsmData->addNodeReference( coordinates, osmData ); return &placemarkOsmData->nodeReference( coordinates ); } /* Case 3: This is the OsmPlacemarkData of a polygon's member * * * * * * ... */ else if ( parser.parentElement( 1 ).is() && parser.parentElement().is() && parser.parentElement( 3 ).is() ) { OsmPlacemarkData *placemarkOsmData = parser.parentElement( 1 ).nodeAs(); GeoDataPlacemark *placemark = parser.parentElement( 3 ).nodeAs(); GeoDataLinearRing &ring = *parser.parentElement().nodeAs(); - if ( placemark->geometry()->nodeType() != GeoDataTypes::GeoDataPolygonType ) { + GeoDataPolygon *polygon = geodata_cast(placemark->geometry()); + if (!polygon) { return 0; } - GeoDataPolygon *polygon = static_cast( placemark->geometry() ); /* The QVector's indexOf function is perfect: returns the index of the ring * within the vector if the ring is an innerBoundary; * Else it returns -1, meaning it's an outerBoundary */ int memberIndex = polygon->innerBoundaries().indexOf( ring ); placemarkOsmData->addMemberReference( memberIndex, osmData ); return &placemarkOsmData->memberReference( memberIndex ); } return 0; } } } diff --git a/src/lib/marble/geodata/handlers/kml/KmlSimpleArrayDataTagHandler.cpp b/src/lib/marble/geodata/handlers/kml/KmlSimpleArrayDataTagHandler.cpp index 072e6d0aa..f24ac0496 100644 --- a/src/lib/marble/geodata/handlers/kml/KmlSimpleArrayDataTagHandler.cpp +++ b/src/lib/marble/geodata/handlers/kml/KmlSimpleArrayDataTagHandler.cpp @@ -1,61 +1,58 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2011 Niko Sams // #include "KmlSimpleArrayDataTagHandler.h" #include "MarbleDebug.h" #include "KmlElementDictionary.h" #include "GeoDataExtendedData.h" #include "GeoDataSimpleArrayData.h" #include "GeoDataSchemaData.h" #include "GeoDataTypes.h" #include "GeoParser.h" #include "GeoDocument.h" namespace Marble { namespace kml { KML_DEFINE_TAG_HANDLER_GX22( SimpleArrayData ) GeoNode* KmlSimpleArrayDataTagHandler::parse( GeoParser& parser ) const { Q_ASSERT(parser.isStartElement() && parser.isValidElement(QLatin1String(kmlTag_SimpleArrayData))); GeoStackItem parentItem = parser.parentElement(); if ( parentItem.is() ) { GeoDataSimpleArrayData *arrayData = new GeoDataSimpleArrayData(); QString name = parser.attribute( "name" ).trimmed(); parentItem.nodeAs()->setSimpleArrayData( name, arrayData ); return arrayData; } if ( parentItem.is() ) { GeoNode *parent = parentItem.nodeAs()->parent(); - if ( parent->nodeType() == GeoDataTypes::GeoDataExtendedDataType ) { - GeoDataExtendedData *extendedData = static_cast( parent ); - if ( extendedData ) { - GeoDataSimpleArrayData *arrayData = new GeoDataSimpleArrayData; - QString name = parser.attribute( "name" ).trimmed(); - extendedData->setSimpleArrayData( name, arrayData ); - return arrayData; - } + if (GeoDataExtendedData *extendedData = geodata_cast(parent)) { + GeoDataSimpleArrayData *arrayData = new GeoDataSimpleArrayData; + const QString name = parser.attribute("name").trimmed(); + extendedData->setSimpleArrayData(name, arrayData); + return arrayData; } } return 0; } } } diff --git a/src/lib/marble/geodata/writers/kml/KmlAnimatedUpdateTagWriter.cpp b/src/lib/marble/geodata/writers/kml/KmlAnimatedUpdateTagWriter.cpp index daeac596e..e1e015e5b 100644 --- a/src/lib/marble/geodata/writers/kml/KmlAnimatedUpdateTagWriter.cpp +++ b/src/lib/marble/geodata/writers/kml/KmlAnimatedUpdateTagWriter.cpp @@ -1,45 +1,45 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Sanjiban Bairagya // #include "KmlAnimatedUpdateTagWriter.h" #include "GeoDataAnimatedUpdate.h" #include "GeoDataTypes.h" #include "GeoDataUpdate.h" #include "GeoWriter.h" #include "KmlElementDictionary.h" #include "KmlObjectTagWriter.h" namespace Marble { static GeoTagWriterRegistrar s_writerAnimatedUpdate( GeoTagWriter::QualifiedName( GeoDataTypes::GeoDataAnimatedUpdateType, kml::kmlTag_nameSpaceOgc22 ), new KmlAnimatedUpdateTagWriter ); bool KmlAnimatedUpdateTagWriter::write( const GeoNode *node, GeoWriter& writer ) const { - Q_ASSERT( node->nodeType() == GeoDataTypes::GeoDataAnimatedUpdateType ); + Q_ASSERT(geodata_cast(node)); const GeoDataAnimatedUpdate *animUpdate = static_cast( node ); writer.writeStartElement( kml::kmlTag_nameSpaceGx22, kml::kmlTag_AnimatedUpdate ); KmlObjectTagWriter::writeIdentifiers( writer, animUpdate ); writer.writeOptionalElement( "gx:duration", animUpdate->duration(), 0.0 ); if ( animUpdate->update() ){ GeoDataUpdate const *update = dynamic_cast( animUpdate->update() ); if( update ){ writeElement( update, writer ); } } writer.writeOptionalElement( "gx:delayedStart", animUpdate->delayedStart(), 0.0 ); writer.writeEndElement(); return true; } } diff --git a/src/lib/marble/geodata/writers/kml/KmlFeatureTagWriter.cpp b/src/lib/marble/geodata/writers/kml/KmlFeatureTagWriter.cpp index a3cb1212e..281566690 100644 --- a/src/lib/marble/geodata/writers/kml/KmlFeatureTagWriter.cpp +++ b/src/lib/marble/geodata/writers/kml/KmlFeatureTagWriter.cpp @@ -1,115 +1,113 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2013 Dennis Nienhüser // #include "KmlFeatureTagWriter.h" -#include "GeoDataTypes.h" #include "GeoDataOverlay.h" #include "GeoDataTimeStamp.h" #include "GeoDataTimeSpan.h" #include "GeoDataDocument.h" #include "GeoDataStyle.h" #include "GeoDataStyleMap.h" #include "GeoDataExtendedData.h" #include "GeoDataLookAt.h" +#include "GeoDataPlacemark.h" #include "GeoDataCamera.h" #include "GeoWriter.h" #include "GeoDataRegion.h" #include "GeoDataLatLonAltBox.h" #include "KmlElementDictionary.h" #include "KmlObjectTagWriter.h" #include "KmlOsmPlacemarkDataTagWriter.h" #include "OsmPlacemarkData.h" #include namespace Marble { KmlFeatureTagWriter::KmlFeatureTagWriter(const QString &elementName) : m_elementName( elementName ) { // nothing to do } bool KmlFeatureTagWriter::write( const Marble::GeoNode *node, GeoWriter &writer ) const { - if ( node->nodeType() == GeoDataTypes::GeoDataDocumentType ) { - const GeoDataDocument *document = static_cast(node); - + if (const GeoDataDocument *document = geodata_cast(node)) { // when a document has only one feature and no styling // the document tag is excused if( (document->id().isEmpty()) && (document->name().isEmpty()) && (document->targetId().isEmpty()) && (document->styles().count() == 0) && (document->styleMaps().count() == 0) && (document->extendedData().isEmpty()) && (document->featureList().count() == 1) ) { writeElement( document->featureList()[0], writer ); return true; } } writer.writeStartElement( m_elementName ); GeoDataFeature const *feature = static_cast(node); KmlObjectTagWriter::writeIdentifiers( writer, feature ); writer.writeOptionalElement( kml::kmlTag_name, feature->name() ); writer.writeOptionalElement( kml::kmlTag_visibility, QString::number( feature->isVisible() ), "1" ); writer.writeOptionalElement( "address", feature->address() ); if( !feature->description().isEmpty() ) { writer.writeStartElement( "description" ); if( feature->descriptionIsCDATA() ) { writer.writeCDATA( feature->description() ); } else { writer.writeCharacters( feature->description() ); } writer.writeEndElement(); } GeoDataLookAt const * lookAt = dynamic_cast( feature->abstractView() ); if ( lookAt ) { writeElement( lookAt, writer ); } GeoDataCamera const * camera = dynamic_cast( feature->abstractView() ); if ( camera ) { writeElement( camera, writer ); } if( feature->timeStamp().when().isValid() ) { writeElement( &feature->timeStamp(), writer ); } if( feature->timeSpan().isValid() ) { writeElement( &feature->timeSpan(), writer ); } if ( !feature->region().latLonAltBox().isNull() ) { writeElement( &feature->region(), writer ); } bool const result = writeMid( node, writer ); - if (feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { + if (geodata_cast(feature)) { KmlOsmPlacemarkDataTagWriter::write(feature, writer); } if( !feature->extendedData().isEmpty() ) { writeElement( &feature->extendedData(), writer ); } writer.writeEndElement(); return result; } } diff --git a/src/lib/marble/geodata/writers/kml/KmlOsmPlacemarkDataTagWriter.cpp b/src/lib/marble/geodata/writers/kml/KmlOsmPlacemarkDataTagWriter.cpp index a4df53b66..3387df134 100644 --- a/src/lib/marble/geodata/writers/kml/KmlOsmPlacemarkDataTagWriter.cpp +++ b/src/lib/marble/geodata/writers/kml/KmlOsmPlacemarkDataTagWriter.cpp @@ -1,120 +1,120 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Marius-Valeriu Stanciu // #include "KmlOsmPlacemarkDataTagWriter.h" #include "GeoDataPlacemark.h" #include "GeoDataSchemaData.h" #include "GeoDataExtendedData.h" #include "GeoDataFeature.h" -#include "GeoDataTypes.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" #include "GeoWriter.h" #include "KmlElementDictionary.h" #include "osm/OsmPlacemarkData.h" namespace Marble { bool KmlOsmPlacemarkDataTagWriter::write( const GeoDataFeature *feature, GeoWriter& writer ) { - if ( feature->nodeType() != GeoDataTypes::GeoDataPlacemarkType ) { + const GeoDataPlacemark *placemark = geodata_cast(feature); + + if (!placemark) { return false; } - const GeoDataPlacemark *placemark = static_cast( feature ); + const OsmPlacemarkData &osmData = placemark->osmData(); if (osmData.isNull()) { return true; } writer.writeStartElement( kml::kmlTag_ExtendedData ); // We declare the "mx" namespace for the custom osmPlacemarkData XML schema writer.writeNamespace( kml::kmlTag_nameSpaceMx, "mx" ); KmlOsmPlacemarkDataTagWriter::writeOsmData( placemark->geometry(), osmData, writer ); writer.writeEndElement(); return true; } bool KmlOsmPlacemarkDataTagWriter::writeOsmData( const GeoDataGeometry *geometry, const OsmPlacemarkData &osmData, GeoWriter& writer ) { writer.writeStartElement( kml::kmlTag_nameSpaceMx, kml::kmlTag_OsmPlacemarkData ); // Writing the attributes writer.writeAttribute( "id", QString::number( osmData.id() ) ); writer.writeOptionalAttribute( "changeset", osmData.changeset() ); writer.writeOptionalAttribute( "timestamp", osmData.timestamp() ); writer.writeOptionalAttribute( "uid", osmData.uid() ); writer.writeOptionalAttribute( "user", osmData.user() ); writer.writeOptionalAttribute( "version", osmData.version() ); writer.writeOptionalAttribute( "visible", osmData.isVisible() ); writer.writeOptionalAttribute( "action", osmData.action() ); // Writing the tags QHash::const_iterator tagsIt = osmData.tagsBegin(); QHash::const_iterator tagsEnd = osmData.tagsEnd(); for ( ; tagsIt != tagsEnd; ++tagsIt ) { writer.writeStartElement( kml::kmlTag_nameSpaceMx, "tag" ); writer.writeAttribute( "k", tagsIt.key() ); writer.writeAttribute( "v", tagsIt.value() ); writer.writeEndElement(); } if ( geometry ) { // Ways if (const GeoDataLineString *lineString = dynamic_cast(geometry)) { int ndIndex = 0; // Writing the component nodes QVector::const_iterator nodeIt = lineString->begin(); QVector::const_iterator nodeEnd = lineString->end(); for ( ; nodeIt != nodeEnd; ++nodeIt ) { const OsmPlacemarkData &nodeOsmData = osmData.nodeReference( *nodeIt ); writer.writeStartElement( kml::kmlTag_nameSpaceMx, "nd" ); writer.writeAttribute( "index", QString::number( ndIndex++ ) ); writeOsmData( nullptr, nodeOsmData, writer ); writer.writeEndElement(); } } // Polygons - else if ( geometry->nodeType() == GeoDataTypes::GeoDataPolygonType ) { + else if (const GeoDataPolygon *polygon = geodata_cast(geometry)) { int memberIndex = -1; // Writing the outerBoundary osmData - const GeoDataPolygon *polygon = static_cast( geometry ); const GeoDataLinearRing &outerRing = polygon->outerBoundary(); const OsmPlacemarkData &outerRingOsmData = osmData.memberReference( memberIndex ); writer.writeStartElement( kml::kmlTag_nameSpaceMx, kml::kmlTag_member ); writer.writeAttribute( "index", QString::number( memberIndex ) ); writeOsmData( &outerRing, outerRingOsmData, writer ); writer.writeEndElement(); // Writing the innerBoundaries for ( const GeoDataLinearRing &innerRing: polygon->innerBoundaries() ) { const OsmPlacemarkData &innerRingOsmData = osmData.memberReference( ++memberIndex ); writer.writeStartElement( kml::kmlTag_nameSpaceMx, kml::kmlTag_member ); writer.writeAttribute( "index", QString::number( memberIndex ) ); writeOsmData( &innerRing, innerRingOsmData, writer ); writer.writeEndElement(); } } } writer.writeEndElement(); return true; } } diff --git a/src/lib/marble/geodata/writers/kml/KmlPlaylistTagWriter.cpp b/src/lib/marble/geodata/writers/kml/KmlPlaylistTagWriter.cpp index f1a2ae700..ad0e35759 100644 --- a/src/lib/marble/geodata/writers/kml/KmlPlaylistTagWriter.cpp +++ b/src/lib/marble/geodata/writers/kml/KmlPlaylistTagWriter.cpp @@ -1,106 +1,108 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2013 Adrian Draghici // #include "KmlPlaylistTagWriter.h" +#include "GeoDataAnimatedUpdate.h" +#include "GeoDataFlyTo.h" #include "GeoDataPlaylist.h" #include "GeoDataTypes.h" #include "GeoDataSoundCue.h" #include "GeoDataWait.h" #include "GeoWriter.h" #include "KmlElementDictionary.h" #include "KmlObjectTagWriter.h" namespace Marble { static GeoTagWriterRegistrar s_writerPlaylist( GeoTagWriter::QualifiedName( GeoDataTypes::GeoDataPlaylistType, kml::kmlTag_nameSpaceOgc22 ), new KmlPlaylistTagWriter ); bool KmlPlaylistTagWriter::write( const GeoNode *node, GeoWriter& writer ) const { const GeoDataPlaylist *playlist = static_cast( node ); writer.writeStartElement( kml::kmlTag_nameSpaceGx22, kml::kmlTag_Playlist ); for ( int i = 0; i < playlist->size(); i++ ) { writeTourPrimitive( playlist->primitive( i ), writer ); } writer.writeEndElement(); return true; } void KmlPlaylistTagWriter::writeTourPrimitive( const GeoNode *primitive, GeoWriter& writer ) const { - if ( primitive->nodeType() == GeoDataTypes::GeoDataTourControlType ) { - writeTourControl(*static_cast(primitive), writer); + if (const auto tourControl = geodata_cast(primitive)) { + writeTourControl(*tourControl, writer); } - else if ( primitive->nodeType() == GeoDataTypes::GeoDataWaitType ) { - writeWait(*static_cast(primitive), writer); + else if (const auto wait = geodata_cast(primitive)) { + writeWait(*wait, writer); } - else if ( primitive->nodeType() == GeoDataTypes::GeoDataFlyToType ) { - writeElement( primitive, writer ); + else if (const auto flyTo = geodata_cast(primitive)) { + writeElement(flyTo, writer); } - else if ( primitive->nodeType() == GeoDataTypes::GeoDataSoundCueType ) { - writeSoundCue(*static_cast(primitive), writer ); + else if (const auto soundCue = geodata_cast(primitive)) { + writeSoundCue(*soundCue, writer); } - else if ( primitive->nodeType() == GeoDataTypes::GeoDataAnimatedUpdateType ) { - writeElement( primitive, writer ); + else if (const auto animatedUpdate = geodata_cast(primitive)) { + writeElement(animatedUpdate, writer); } } void KmlPlaylistTagWriter::writeTourControl(const GeoDataTourControl &tourControl, GeoWriter &writer) { writer.writeStartElement( kml::kmlTag_nameSpaceGx22, kml::kmlTag_TourControl ); KmlObjectTagWriter::writeIdentifiers(writer, &tourControl); writer.writeElement(kml::kmlTag_nameSpaceGx22, kml::kmlTag_playMode, playModeToString(tourControl.playMode())); writer.writeEndElement(); } void KmlPlaylistTagWriter::writeWait(const GeoDataWait &wait, GeoWriter &writer) { writer.writeStartElement( kml::kmlTag_nameSpaceGx22, kml::kmlTag_Wait ); KmlObjectTagWriter::writeIdentifiers(writer, &wait); writer.writeElement(kml::kmlTag_nameSpaceGx22, kml::kmlTag_duration, QString::number(wait.duration())); writer.writeEndElement(); } void KmlPlaylistTagWriter::writeSoundCue(const GeoDataSoundCue &cue, GeoWriter &writer) { writer.writeStartElement( kml::kmlTag_nameSpaceGx22, kml::kmlTag_SoundCue ); KmlObjectTagWriter::writeIdentifiers(writer, &cue); writer.writeElement(kml::kmlTag_href, cue.href()); writer.writeElement( kml::kmlTag_nameSpaceGx22, kml::kmlTag_delayedStart, QString::number(cue.delayedStart())); writer.writeEndElement(); } QString KmlPlaylistTagWriter::playModeToString( GeoDataTourControl::PlayMode playMode ) { switch (playMode) { case GeoDataTourControl::Play: return "play"; case GeoDataTourControl::Pause: return "pause"; default: return ""; } } } diff --git a/src/lib/marble/geodata/writers/kml/KmlTimeSpanWriter.cpp b/src/lib/marble/geodata/writers/kml/KmlTimeSpanWriter.cpp index 55419221b..8f2723982 100644 --- a/src/lib/marble/geodata/writers/kml/KmlTimeSpanWriter.cpp +++ b/src/lib/marble/geodata/writers/kml/KmlTimeSpanWriter.cpp @@ -1,47 +1,46 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2012 Shou Ya // #include "KmlTimeSpanWriter.h" #include "GeoDataTimeSpan.h" #include "GeoDataTypes.h" #include "GeoWriter.h" #include "KmlElementDictionary.h" #include "KmlTimeStampTagWriter.h" #include "KmlObjectTagWriter.h" namespace Marble { static GeoTagWriterRegistrar s_writerLookAt( GeoTagWriter::QualifiedName( GeoDataTypes::GeoDataTimeSpanType, kml::kmlTag_nameSpaceOgc22 ), new KmlTimeSpanWriter ); bool KmlTimeSpanWriter::write( const GeoNode *node, GeoWriter& writer ) const { - Q_ASSERT( node->nodeType() == GeoDataTypes::GeoDataTimeSpanType ); - const GeoDataTimeSpan *timespan = - static_cast( node ); + const GeoDataTimeSpan *timespan = geodata_cast(node); + Q_ASSERT(timespan); writer.writeStartElement( kml::kmlTag_TimeSpan ); KmlObjectTagWriter::writeIdentifiers( writer, timespan ); writer.writeTextElement( "begin", KmlTimeStampTagWriter::toString( timespan->begin() ) ); writer.writeTextElement( "end", KmlTimeStampTagWriter::toString( timespan->end() ) ); writer.writeEndElement(); return true; } } diff --git a/src/lib/marble/graphicsview/GeoGraphicsItem.cpp b/src/lib/marble/graphicsview/GeoGraphicsItem.cpp index 0bc4077cf..4f0f009a5 100644 --- a/src/lib/marble/graphicsview/GeoGraphicsItem.cpp +++ b/src/lib/marble/graphicsview/GeoGraphicsItem.cpp @@ -1,229 +1,227 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2009 Bastian Holst // // Self #include "GeoGraphicsItem.h" #include "GeoGraphicsItem_p.h" -#include "GeoDataTypes.h" #include "GeoDataPlacemark.h" // Qt #include "MarbleDebug.h" #include using namespace Marble; GeoGraphicsItem::GeoGraphicsItem( const GeoDataFeature *feature ) : d( new GeoGraphicsItemPrivate( feature ) ) { setFlag( ItemIsVisible, true ); } GeoGraphicsItem::~GeoGraphicsItem() { delete d; } bool GeoGraphicsItem::visible() const { return d->m_flags & ItemIsVisible; } void GeoGraphicsItem::setVisible( bool visible ) { setFlag( ItemIsVisible, visible ); } GeoGraphicsItem::GeoGraphicsItemFlags GeoGraphicsItem::flags() const { return d->m_flags; } void GeoGraphicsItem::setFlag( GeoGraphicsItemFlag flag, bool enabled ) { if( enabled ) { d->m_flags = d->m_flags | flag; } else { d->m_flags = d->m_flags & ~flag; } } void GeoGraphicsItem::setFlags( GeoGraphicsItemFlags flags ) { d->m_flags = flags; } const GeoDataFeature* GeoGraphicsItem::feature() const { return d->m_feature; } void GeoGraphicsItem::setHighlightStyle( const GeoDataStyle::ConstPtr &highlightStyle) { /** * Delete any previously set style * and assign the new style @highlightStyle */ d->m_highlightStyle = highlightStyle; } GeoDataStyle::ConstPtr GeoGraphicsItem::style() const { /** * m_isHighlight is set true when the item is * supposed to be colored highlighted */ if ( d->m_highlighted && d->m_highlightStyle ) { return d->m_highlightStyle; } if (!d->m_style) { - if (d->m_feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - const GeoDataPlacemark *placemark = static_cast(d->m_feature); + if (const GeoDataPlacemark *placemark = geodata_cast(d->m_feature)) { auto styling = StyleParameters(placemark, d->m_renderContext.tileLevel()); for (auto relation: d->m_relations) { if (relation->isVisible()) { styling.relation = relation; break; } } d->m_style = d->m_styleBuilder->createStyle(styling); } else { d->m_style = d->m_feature->style(); } } return d->m_style; } void GeoGraphicsItem::setStyleBuilder(const StyleBuilder *styleBuilder) { d->m_styleBuilder = styleBuilder; } void GeoGraphicsItem::resetStyle() { d->m_style = GeoDataStyle::ConstPtr(); handleRelationUpdate(d->m_relations); } qreal GeoGraphicsItem::zValue() const { return d->m_zValue; } void GeoGraphicsItem::setZValue( qreal z ) { d->m_zValue = z; } void GeoGraphicsItem::setHighlighted( bool highlight ) { d->m_highlighted = highlight; } bool GeoGraphicsItem::isHighlighted() const { return d->m_highlighted; } QStringList GeoGraphicsItem::paintLayers() const { return d->m_paintLayers; } void GeoGraphicsItem::setPaintLayers(const QStringList &paintLayers) { d->m_paintLayers = paintLayers; } void GeoGraphicsItem::setRenderContext(const RenderContext &renderContext) { if (renderContext != d->m_renderContext) { d->m_renderContext = renderContext; d->m_style = GeoDataStyle::ConstPtr(); } } bool GeoGraphicsItem::contains(const QPoint &, const ViewportParams *) const { return false; } void GeoGraphicsItem::setRelations(const QSet &relations) { d->m_relations.clear(); std::copy(relations.begin(), relations.end(), std::back_inserter(d->m_relations)); std::sort(d->m_relations.begin(), d->m_relations.end(), [](const GeoDataRelation * a, const GeoDataRelation * b) { return *a < *b; }); d->m_style = GeoDataStyle::ConstPtr(); handleRelationUpdate(d->m_relations); } void GeoGraphicsItem::handleRelationUpdate(const QVector &) { // does nothing } int GeoGraphicsItem::minZoomLevel() const { return d->m_minZoomLevel; } void GeoGraphicsItem::setMinZoomLevel(int zoomLevel) { d->m_minZoomLevel = zoomLevel; } bool GeoGraphicsItem::zValueLessThan(GeoGraphicsItem *one, GeoGraphicsItem *two) { return one->d->m_zValue < two->d->m_zValue; } bool GeoGraphicsItem::styleLessThan(GeoGraphicsItem *one, GeoGraphicsItem *two) { return reinterpret_cast(one->d->m_style.data()) < reinterpret_cast(two->d->m_style.data()); } bool GeoGraphicsItem::zValueAndStyleLessThan(GeoGraphicsItem *one, GeoGraphicsItem *two) { if (one->d->m_zValue == two->d->m_zValue) { return reinterpret_cast(one->d->m_style.data()) < reinterpret_cast(two->d->m_style.data()); } return one->d->m_zValue < two->d->m_zValue; } bool RenderContext::operator==(const RenderContext &other) const { return m_tileLevel == other.m_tileLevel; } bool RenderContext::operator!=(const RenderContext &other) const { return !operator==(other); } int RenderContext::tileLevel() const { return m_tileLevel; } RenderContext::RenderContext(int tileLevel) : m_tileLevel(tileLevel) { // nothing to do } diff --git a/src/lib/marble/layers/GeometryLayer.cpp b/src/lib/marble/layers/GeometryLayer.cpp index dcaafb69f..78084a912 100644 --- a/src/lib/marble/layers/GeometryLayer.cpp +++ b/src/lib/marble/layers/GeometryLayer.cpp @@ -1,698 +1,673 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2008-2009 Patrick Spendrin // Copyright 2010 Thibaut Gridel // Copyright 2011-2012 Bernhard Beschow // Copyright 2014 Gábor Péterffy // #include "GeometryLayer.h" // Marble #include "GeoDataLatLonAltBox.h" #include "GeoDataDocument.h" #include "GeoDataFolder.h" #include "GeoDataLineStyle.h" #include "GeoDataMultiTrack.h" #include "GeoDataObject.h" #include "GeoDataPlacemark.h" #include "GeoDataLinearRing.h" #include "GeoDataMultiGeometry.h" #include "GeoDataPolygon.h" #include "GeoDataPolyStyle.h" #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include "GeoDataStyleMap.h" #include "GeoDataTrack.h" -#include "GeoDataTypes.h" #include "GeoDataFeature.h" #include "MarbleDebug.h" #include "GeoPainter.h" #include "ViewportParams.h" #include "RenderState.h" #include "GeoGraphicsScene.h" #include "GeoGraphicsItem.h" #include "GeoLineStringGraphicsItem.h" #include "GeoPolygonGraphicsItem.h" #include "GeoTrackGraphicsItem.h" #include "GeoDataPhotoOverlay.h" #include "GeoDataScreenOverlay.h" #include "GeoPhotoGraphicsItem.h" #include "ScreenOverlayGraphicsItem.h" #include "TileId.h" #include "MarbleGraphicsItem.h" #include "MarblePlacemarkModel.h" #include "GeoDataTreeModel.h" #include #include "StyleBuilder.h" #include "AbstractGeoPolygonGraphicsItem.h" #include "GeoLineStringGraphicsItem.h" #include "GeoDataRelation.h" // Qt #include #include #include namespace Marble { class GeometryLayerPrivate { public: typedef QVector OsmLineStringItems; typedef QSet Relations; typedef QHash FeatureRelationHash; typedef QVector GeoGraphicItems; struct PaintFragments { // Three lists for different z values // A z value of 0 is default and used by the majority of items, so sorting // can be avoided for it QVector negative; // subways QVector null; // areas and roads QVector positive; // buildings }; explicit GeometryLayerPrivate(const QAbstractItemModel *model, const StyleBuilder *styleBuilder); void createGraphicsItems(const GeoDataObject *object); void createGraphicsItems(const GeoDataObject *object, FeatureRelationHash &relations); void createGraphicsItemFromGeometry(const GeoDataGeometry *object, const GeoDataPlacemark *placemark, const Relations &relations); void createGraphicsItemFromOverlay(const GeoDataOverlay *overlay); void removeGraphicsItems(const GeoDataFeature *feature); void updateTiledLineStrings(const GeoDataPlacemark *placemark, GeoLineStringGraphicsItem* lineStringItem); void updateTiledLineStrings(OsmLineStringItems &lineStringItems); void clearCache(); bool showRelation(const GeoDataRelation* relation) const; void updateRelationVisibility(); const QAbstractItemModel *const m_model; const StyleBuilder *const m_styleBuilder; GeoGraphicsScene m_scene; QString m_runtimeTrace; QList m_screenOverlays; QHash m_osmLineStringItems; int m_tileLevel; GeoGraphicsItem* m_lastFeatureAt; bool m_dirty; int m_cachedItemCount; QHash m_cachedPaintFragments; typedef QPair LayerItem; QList m_cachedDefaultLayer; QDateTime m_cachedDateTime; GeoDataLatLonBox m_cachedLatLonBox; QSet m_highlightedRouteRelations; bool m_showPublicTransport; }; GeometryLayerPrivate::GeometryLayerPrivate(const QAbstractItemModel *model, const StyleBuilder *styleBuilder) : m_model(model), m_styleBuilder(styleBuilder), m_tileLevel(0), m_lastFeatureAt(nullptr), m_dirty(true), m_cachedItemCount(0), m_showPublicTransport(false) { } void GeometryLayerPrivate::createGraphicsItems(const GeoDataObject *object) { FeatureRelationHash noRelations; createGraphicsItems(object, noRelations); } GeometryLayer::GeometryLayer(const QAbstractItemModel *model, const StyleBuilder *styleBuilder) : d(new GeometryLayerPrivate(model, styleBuilder)) { const GeoDataObject *object = static_cast(d->m_model->index(0, 0, QModelIndex()).internalPointer()); if (object && object->parent()) { d->createGraphicsItems(object->parent()); } connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(resetCacheData())); connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(addPlacemarks(QModelIndex, int, int))); connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), this, SLOT(removePlacemarks(QModelIndex, int, int))); connect(model, SIGNAL(modelReset()), this, SLOT(resetCacheData())); connect(this, SIGNAL(highlightedPlacemarksChanged(QVector)), &d->m_scene, SLOT(applyHighlight(QVector))); connect(&d->m_scene, SIGNAL(repaintNeeded()), this, SIGNAL(repaintNeeded())); } GeometryLayer::~GeometryLayer() { delete d; } QStringList GeometryLayer::renderPosition() const { return QStringList(QStringLiteral("HOVERS_ABOVE_SURFACE")); } bool GeometryLayer::render(GeoPainter *painter, ViewportParams *viewport, const QString& renderPos, GeoSceneLayer * layer) { Q_UNUSED(renderPos) Q_UNUSED(layer) painter->save(); auto const & box = viewport->viewLatLonAltBox(); bool isEqual = GeoDataLatLonBox::fuzzyCompare(d->m_cachedLatLonBox, box, 0.05); if (d->m_cachedLatLonBox.isEmpty() || !isEqual) { d->m_dirty = true; } // update the items cache at least every second since the last request auto const now = QDateTime::currentDateTime(); if (!d->m_cachedDateTime.isValid() || d->m_cachedDateTime.msecsTo(now) > 1000) { d->m_dirty = true; } if (d->m_dirty) { d->m_dirty = false; const int maxZoomLevel = qMin(d->m_tileLevel, d->m_styleBuilder->maximumZoomLevel()); auto const items = d->m_scene.items(box, maxZoomLevel);; d->m_cachedLatLonBox = box; d->m_cachedDateTime = now; d->m_cachedItemCount = items.size(); d->m_cachedDefaultLayer.clear(); d->m_cachedPaintFragments.clear(); QHash paintFragments; QSet const knownLayers = QSet::fromList(d->m_styleBuilder->renderOrder()); for (GeoGraphicsItem* item: items) { QStringList paintLayers = item->paintLayers(); if (paintLayers.isEmpty()) { mDebug() << item << " provides no paint layers, so I force one onto it."; paintLayers << QString(); } for (const auto &layer: paintLayers) { if (knownLayers.contains(layer)) { GeometryLayerPrivate::PaintFragments &fragments = paintFragments[layer]; double const zValue = item->zValue(); // assign subway stations if (zValue == 0.0) { fragments.null << item; // assign areas and streets } else if (zValue < 0.0) { fragments.negative << item; // assign buildings } else { fragments.positive << item; } } else { // assign symbols d->m_cachedDefaultLayer << GeometryLayerPrivate::LayerItem(layer, item); static QSet missingLayers; if (!missingLayers.contains(layer)) { mDebug() << "Missing layer " << layer << ", in render order, will render it on top"; missingLayers << layer; } } } } // Sort each fragment by z-level for (const QString &layer: d->m_styleBuilder->renderOrder()) { GeometryLayerPrivate::PaintFragments & layerItems = paintFragments[layer]; std::sort(layerItems.negative.begin(), layerItems.negative.end(), GeoGraphicsItem::zValueLessThan); // The idea here is that layerItems.null has most items and does not need to be sorted by z-value // since they are all equal (=0). We do sort them by style pointer though for batch rendering std::sort(layerItems.null.begin(), layerItems.null.end(), GeoGraphicsItem::styleLessThan); std::sort(layerItems.positive.begin(), layerItems.positive.end(), GeoGraphicsItem::zValueAndStyleLessThan); auto const count = layerItems.negative.size() + layerItems.null.size() + layerItems.positive.size(); d->m_cachedPaintFragments[layer].reserve(count); d->m_cachedPaintFragments[layer] << layerItems.negative; d->m_cachedPaintFragments[layer] << layerItems.null; d->m_cachedPaintFragments[layer] << layerItems.positive; } } for (const QString &layer: d->m_styleBuilder->renderOrder()) { auto & layerItems = d->m_cachedPaintFragments[layer]; AbstractGeoPolygonGraphicsItem::s_previousStyle = 0; GeoLineStringGraphicsItem::s_previousStyle = 0; for (auto item: layerItems) { item->paint(painter, viewport, layer, d->m_tileLevel); } } for (const auto & item: d->m_cachedDefaultLayer) { item.second->paint(painter, viewport, item.first, d->m_tileLevel); } for (ScreenOverlayGraphicsItem* item: d->m_screenOverlays) { item->paintEvent(painter, viewport); } painter->restore(); d->m_runtimeTrace = QStringLiteral("Geometries: %1 Zoom: %2") .arg(d->m_cachedItemCount) .arg(d->m_tileLevel); return true; } RenderState GeometryLayer::renderState() const { return RenderState(QStringLiteral("GeoGraphicsScene")); } QString GeometryLayer::runtimeTrace() const { return d->m_runtimeTrace; } bool GeometryLayer::hasFeatureAt(const QPoint &curpos, const ViewportParams *viewport) { if (d->m_lastFeatureAt && d->m_lastFeatureAt->contains(curpos, viewport)) { return true; } auto const renderOrder = d->m_styleBuilder->renderOrder(); for (int i = renderOrder.size() - 1; i >= 0; --i) { auto & layerItems = d->m_cachedPaintFragments[renderOrder[i]]; for (auto item : layerItems) { if (item->contains(curpos, viewport)) { d->m_lastFeatureAt = item; return true; } } } return false; } void GeometryLayerPrivate::createGraphicsItems(const GeoDataObject *object, FeatureRelationHash &relations) { clearCache(); - if (object->nodeType() == GeoDataTypes::GeoDataDocumentType) { - auto document = static_cast(object); + if (auto document = geodata_cast(object)) { for (auto feature: document->featureList()) { - if (feature->nodeType() == GeoDataTypes::GeoDataRelationType) { - auto relation = static_cast(feature); + if (auto relation = geodata_cast(feature)) { relation->setVisible(showRelation(relation)); for (auto member: relation->members()) { relations[member] << relation; } } } } - if (object->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - auto placemark = static_cast(object); + if (auto placemark = geodata_cast(object)) { createGraphicsItemFromGeometry(placemark->geometry(), placemark, relations.value(placemark)); } else if (const GeoDataOverlay* overlay = dynamic_cast(object)) { createGraphicsItemFromOverlay(overlay); } // parse all child objects of the container if (const GeoDataContainer *container = dynamic_cast(object)) { int rowCount = container->size(); for (int row = 0; row < rowCount; ++row) { createGraphicsItems(container->child(row), relations); } } } void GeometryLayerPrivate::updateTiledLineStrings(const GeoDataPlacemark* placemark, GeoLineStringGraphicsItem* lineStringItem) { if (!placemark->hasOsmData()) { return; } qint64 const osmId = placemark->osmData().oid(); if (osmId <= 0) { return; } auto & lineStringItems = m_osmLineStringItems[osmId]; lineStringItems << lineStringItem; updateTiledLineStrings(lineStringItems); } void GeometryLayerPrivate::updateTiledLineStrings(OsmLineStringItems &lineStringItems) { GeoDataLineString merged; if (lineStringItems.size() > 1) { QVector lineStrings; for (auto item : lineStringItems) { lineStrings << item->lineString(); } merged = GeoLineStringGraphicsItem::merge(lineStrings); } // If merging failed, reset all. Otherwise only the first one // gets the merge result and becomes visible. bool visible = true; for (auto item : lineStringItems) { item->setVisible(visible); if (visible) { item->setMergedLineString(merged); visible = merged.isEmpty(); } } } void GeometryLayerPrivate::clearCache() { m_lastFeatureAt = nullptr; m_dirty = true; m_cachedDateTime = QDateTime(); m_cachedItemCount = 0; m_cachedPaintFragments.clear(); m_cachedDefaultLayer.clear(); m_cachedLatLonBox = GeoDataLatLonBox(); } inline bool GeometryLayerPrivate::showRelation(const GeoDataRelation *relation) const { return (m_showPublicTransport && relation->relationType() >= GeoDataRelation::RouteTrain && relation->relationType() <= GeoDataRelation::RouteTrolleyBus) || m_highlightedRouteRelations.contains(relation->osmData().oid()); } void GeometryLayerPrivate::updateRelationVisibility() { for (int i = 0; i < m_model->rowCount(); ++i) { QVariant const data = m_model->data(m_model->index(i, 0), MarblePlacemarkModel::ObjectPointerRole); GeoDataObject *object = qvariant_cast (data); - if (object->nodeType() == GeoDataTypes::GeoDataDocumentType) { - GeoDataDocument* doc = static_cast(object); + if (auto doc = geodata_cast(object)) { for (auto feature: doc->featureList()) { - if (feature->nodeType() == GeoDataTypes::GeoDataRelationType) { - auto relation = static_cast(feature); + if (auto relation = geodata_cast(feature)) { relation->setVisible(showRelation(relation)); } } } } m_scene.resetStyle(); } void GeometryLayerPrivate::createGraphicsItemFromGeometry(const GeoDataGeometry* object, const GeoDataPlacemark *placemark, const Relations &relations) { if (!placemark->isGloballyVisible()) { return; // Reconsider this when visibility can be changed dynamically } GeoGraphicsItem *item = 0; - if (object->nodeType() == GeoDataTypes::GeoDataLineStringType) { - const GeoDataLineString* line = static_cast(object); + if (const auto line = geodata_cast(object)) { auto lineStringItem = new GeoLineStringGraphicsItem(placemark, line); item = lineStringItem; updateTiledLineStrings(placemark, lineStringItem); - } else if (object->nodeType() == GeoDataTypes::GeoDataLinearRingType) { - const GeoDataLinearRing *ring = static_cast(object); + } else if (const auto ring = geodata_cast(object)) { item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, ring); - } else if (object->nodeType() == GeoDataTypes::GeoDataPolygonType) { - const GeoDataPolygon *poly = static_cast(object); + } else if (const auto poly = geodata_cast(object)) { item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, poly); if (item->zValue() == 0) { item->setZValue(poly->renderOrder()); } - } else if (object->nodeType() == GeoDataTypes::GeoDataMultiGeometryType) { - const GeoDataMultiGeometry *multigeo = static_cast(object); + } else if (const auto multigeo = geodata_cast(object)) { int rowCount = multigeo->size(); for (int row = 0; row < rowCount; ++row) { createGraphicsItemFromGeometry(multigeo->child(row), placemark, relations); } - } else if (object->nodeType() == GeoDataTypes::GeoDataMultiTrackType) { - const GeoDataMultiTrack *multitrack = static_cast(object); + } else if (const auto multitrack = geodata_cast(object)) { int rowCount = multitrack->size(); for (int row = 0; row < rowCount; ++row) { createGraphicsItemFromGeometry(multitrack->child(row), placemark, relations); } - } else if (object->nodeType() == GeoDataTypes::GeoDataTrackType) { - const GeoDataTrack *track = static_cast(object); + } else if (const auto track = geodata_cast(object)) { item = new GeoTrackGraphicsItem(placemark, track); } if (!item) { return; } item->setRelations(relations); item->setStyleBuilder(m_styleBuilder); item->setVisible(item->visible() && placemark->isGloballyVisible()); item->setMinZoomLevel(m_styleBuilder->minimumZoomLevel(*placemark)); m_scene.addItem(item); } void GeometryLayerPrivate::createGraphicsItemFromOverlay(const GeoDataOverlay *overlay) { if (!overlay->isGloballyVisible()) { return; // Reconsider this when visibility can be changed dynamically } GeoGraphicsItem* item = 0; - if (overlay->nodeType() == GeoDataTypes::GeoDataPhotoOverlayType) { - GeoDataPhotoOverlay const * photoOverlay = static_cast(overlay); + if (const auto photoOverlay = geodata_cast(overlay)) { GeoPhotoGraphicsItem *photoItem = new GeoPhotoGraphicsItem(overlay); photoItem->setPoint(photoOverlay->point()); item = photoItem; - } else if (overlay->nodeType() == GeoDataTypes::GeoDataScreenOverlayType) { - GeoDataScreenOverlay const * screenOverlay = static_cast(overlay); + } else if (const auto screenOverlay = geodata_cast(overlay)) { ScreenOverlayGraphicsItem *screenItem = new ScreenOverlayGraphicsItem(screenOverlay); m_screenOverlays.push_back(screenItem); } if (item) { item->setStyleBuilder(m_styleBuilder); item->setVisible(overlay->isGloballyVisible()); m_scene.addItem(item); } } void GeometryLayerPrivate::removeGraphicsItems(const GeoDataFeature *feature) { clearCache(); - if (feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - GeoDataPlacemark const * placemark = static_cast(feature); + if (const auto placemark = geodata_cast(feature)) { if (placemark->isGloballyVisible() && - placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType && + geodata_cast(placemark->geometry()) && placemark->hasOsmData() && placemark->osmData().oid() > 0) { auto & items = m_osmLineStringItems[placemark->osmData().oid()]; bool removed = false; for (auto item : items) { if (item->feature() == feature) { items.removeOne(item); removed = true; break; } } Q_ASSERT(removed); updateTiledLineStrings(items); } m_scene.removeItem(feature); } else if (const auto container = dynamic_cast(feature)) { for (const GeoDataFeature *child: container->featureList()) { removeGraphicsItems(child); } - } else if (feature->nodeType() == GeoDataTypes::GeoDataScreenOverlayType) { + } else if (geodata_cast(feature)) { for (ScreenOverlayGraphicsItem *item: m_screenOverlays) { if (item->screenOverlay() == feature) { m_screenOverlays.removeAll(item); } } } } void GeometryLayer::addPlacemarks(const QModelIndex& parent, int first, int last) { Q_ASSERT(first < d->m_model->rowCount(parent)); Q_ASSERT(last < d->m_model->rowCount(parent)); for (int i = first; i <= last; ++i) { QModelIndex index = d->m_model->index(i, 0, parent); Q_ASSERT(index.isValid()); const GeoDataObject *object = qvariant_cast(index.data(MarblePlacemarkModel::ObjectPointerRole)); Q_ASSERT(object); d->createGraphicsItems(object); } emit repaintNeeded(); } void GeometryLayer::removePlacemarks(const QModelIndex& parent, int first, int last) { Q_ASSERT(last < d->m_model->rowCount(parent)); bool isRepaintNeeded = false; for (int i = first; i <= last; ++i) { QModelIndex index = d->m_model->index(i, 0, parent); Q_ASSERT(index.isValid()); const GeoDataObject *object = qvariant_cast(index.data(MarblePlacemarkModel::ObjectPointerRole)); const GeoDataFeature *feature = dynamic_cast(object); if (feature != 0) { d->removeGraphicsItems(feature); isRepaintNeeded = true; } } if (isRepaintNeeded) { emit repaintNeeded(); } } void GeometryLayer::resetCacheData() { d->clearCache(); d->m_scene.clear(); qDeleteAll(d->m_screenOverlays); d->m_screenOverlays.clear(); d->m_osmLineStringItems.clear(); const GeoDataObject *object = static_cast(d->m_model->index(0, 0, QModelIndex()).internalPointer()); if (object && object->parent()) { d->createGraphicsItems(object->parent()); } emit repaintNeeded(); } void GeometryLayer::setTileLevel(int tileLevel) { d->m_tileLevel = tileLevel; } QVector GeometryLayer::whichFeatureAt(const QPoint &curpos, const ViewportParams *viewport) { QVector result; auto const renderOrder = d->m_styleBuilder->renderOrder(); QString const label = QStringLiteral("/label"); QSet checked; for (int i = renderOrder.size()-1; i >= 0; --i) { if (renderOrder[i].endsWith(label)) { continue; } auto & layerItems = d->m_cachedPaintFragments[renderOrder[i]]; for (auto j = layerItems.size()-1; j >= 0; --j) { auto const & layerItem = layerItems[j]; if (!checked.contains(layerItem)) { if (layerItem->contains(curpos, viewport)) { result << layerItem->feature(); } checked << layerItem; } } } return result; } void GeometryLayer::highlightRouteRelation(qint64 osmId, bool enabled) { if (enabled) { d->m_highlightedRouteRelations << osmId; } else { d->m_highlightedRouteRelations.remove(osmId); } d->updateRelationVisibility(); } void GeometryLayer::setShowPublicTransport(bool showPublicTransport) { if (showPublicTransport == d->m_showPublicTransport) { return; } d->m_showPublicTransport = showPublicTransport; d->updateRelationVisibility(); } void GeometryLayer::handleHighlight(qreal lon, qreal lat, GeoDataCoordinates::Unit unit) { GeoDataCoordinates clickedPoint(lon, lat, 0, unit); QVector selectedPlacemarks; for (int i = 0; i < d->m_model->rowCount(); ++i) { QVariant const data = d->m_model->data(d->m_model->index(i, 0), MarblePlacemarkModel::ObjectPointerRole); GeoDataObject *object = qvariant_cast (data); Q_ASSERT(object); - if (object->nodeType() == GeoDataTypes::GeoDataDocumentType) { - Q_ASSERT(dynamic_cast(object) != 0); - GeoDataDocument* doc = static_cast(object); + if (const auto doc = geodata_cast(object)) { bool isHighlight = false; for (const GeoDataStyleMap &styleMap: doc->styleMaps()) { if (styleMap.contains(QStringLiteral("highlight"))) { isHighlight = true; break; } } /* * If a document doesn't specify any highlight * styleId in its style maps then there is no need * to further check that document for placemarks * which have been clicked because we won't * highlight them. */ if (isHighlight) { QVector::Iterator iter = doc->begin(); QVector::Iterator const end = doc->end(); for (; iter != end; ++iter) { - if ((*iter)->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - GeoDataPlacemark *placemark = static_cast(*iter); + if (auto placemark = geodata_cast(*iter)) { GeoDataPolygon *polygon = dynamic_cast(placemark->geometry()); - GeoDataLineString *lineString = dynamic_cast(placemark->geometry()); - GeoDataMultiGeometry *multiGeometry = dynamic_cast(placemark->geometry()); if (polygon && polygon->contains(clickedPoint)) { selectedPlacemarks.push_back(placemark); } - if (lineString && - lineString->nodeType() == GeoDataTypes::GeoDataLinearRingType) { - GeoDataLinearRing *linearRing = static_cast(lineString); + if (auto linearRing = geodata_cast(placemark->geometry())) { if (linearRing->contains(clickedPoint)) { selectedPlacemarks.push_back(placemark); } } - if (multiGeometry) { + if (auto multiGeometry = geodata_cast(placemark->geometry())) { QVector::Iterator multiIter = multiGeometry->begin(); QVector::Iterator const multiEnd = multiGeometry->end(); for (; multiIter != multiEnd; ++multiIter) { GeoDataPolygon *poly = dynamic_cast(*multiIter); - GeoDataLineString *linestring = dynamic_cast(*multiIter); if (poly && poly->contains(clickedPoint)) { selectedPlacemarks.push_back(placemark); break; } - if (linestring && - linestring->nodeType() == GeoDataTypes::GeoDataLinearRingType) { - GeoDataLinearRing *linearRing = static_cast(linestring); + if (auto linearRing = geodata_cast(*multiIter)) { if (linearRing->contains(clickedPoint)) { selectedPlacemarks.push_back(placemark); break; } } } } } } } } } emit highlightedPlacemarksChanged(selectedPlacemarks); } } #include "moc_GeometryLayer.cpp" diff --git a/src/lib/marble/osm/OsmObjectManager.cpp b/src/lib/marble/osm/OsmObjectManager.cpp index a4bb86938..be71b3b7b 100644 --- a/src/lib/marble/osm/OsmObjectManager.cpp +++ b/src/lib/marble/osm/OsmObjectManager.cpp @@ -1,112 +1,108 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Stanciu Marius-Valeriu // // Self #include "OsmObjectManager.h" // Marble #include "GeoDataPlacemark.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" -#include "GeoDataTypes.h" #include "osm/OsmPlacemarkData.h" namespace Marble { qint64 OsmObjectManager::m_minId = -1; void OsmObjectManager::initializeOsmData( GeoDataPlacemark* placemark ) { OsmPlacemarkData &osmData = placemark->osmData(); bool isNull = osmData.isNull(); if ( isNull ) { // The "--m_minId" assignments mean: assigning an id lower( by 1 ) than the current lowest, // and updating the current lowest id. osmData.setId( --m_minId ); } // Assigning osmData to each of the line's nodes ( if they don't already have data ) - if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { - const GeoDataLineString* lineString = static_cast( placemark->geometry() ); + if (const auto lineString = geodata_cast(placemark->geometry())) { QVector::const_iterator it = lineString->constBegin(); QVector::ConstIterator const end = lineString->constEnd(); for ( ; it != end; ++it ) { if (osmData.nodeReference(*it).isNull()) { osmData.nodeReference(*it).setId(--m_minId); } } } // Assigning osmData to each of the line's nodes ( if they don't already have data ) - if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType ) { - const GeoDataLinearRing* lineString = static_cast( placemark->geometry() ); + if (const auto lineString = geodata_cast(placemark->geometry())) { for (auto it =lineString->constBegin(), end = lineString->constEnd(); it != end; ++it ) { if (osmData.nodeReference(*it).isNull()) { osmData.nodeReference(*it).setId(--m_minId); } } } // Assigning osmData to each of the polygons boundaries, and to each of the // nodes that are part of those boundaries ( if they don't already have data ) - if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { - const GeoDataPolygon* polygon = static_cast( placemark->geometry() ); + if (const auto polygon = geodata_cast(placemark->geometry())) { const GeoDataLinearRing &outerBoundary = polygon->outerBoundary(); int index = -1; if ( isNull ) { osmData.addTag(QStringLiteral("type"), QStringLiteral("multipolygon")); } // Outer boundary OsmPlacemarkData &outerBoundaryData = osmData.memberReference( index ); if (outerBoundaryData.isNull()) { outerBoundaryData.setId(--m_minId); } // Outer boundary nodes QVector::const_iterator it = outerBoundary.constBegin(); QVector::ConstIterator const end = outerBoundary.constEnd(); for ( ; it != end; ++it ) { if (outerBoundaryData.nodeReference(*it).isNull()) { outerBoundaryData.nodeReference(*it).setId(--m_minId); } } // Each inner boundary for( const GeoDataLinearRing &innerRing: polygon->innerBoundaries() ) { ++index; OsmPlacemarkData &innerRingData = osmData.memberReference( index ); if (innerRingData.isNull()) { innerRingData.setId(--m_minId); } // Inner boundary nodes QVector::const_iterator it = innerRing.constBegin(); QVector::ConstIterator const end = innerRing.constEnd(); for ( ; it != end; ++it ) { if (innerRingData.nodeReference(*it).isNull()) { innerRingData.nodeReference(*it).setId(--m_minId); } } } } } void OsmObjectManager::registerId( qint64 id ) { m_minId = qMin( id, m_minId ); } } diff --git a/src/lib/marble/osm/OsmRelationManagerWidget.cpp b/src/lib/marble/osm/OsmRelationManagerWidget.cpp index 42858b1c6..b92220d59 100644 --- a/src/lib/marble/osm/OsmRelationManagerWidget.cpp +++ b/src/lib/marble/osm/OsmRelationManagerWidget.cpp @@ -1,176 +1,175 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Stanciu Marius-Valeriu // // Self #include "OsmRelationManagerWidget.h" #include "OsmRelationManagerWidget_p.h" #include "ui_OsmRelationManagerWidget.h" // Qt #include #include #include #include #include // Marble -#include "GeoDataTypes.h" #include "GeoDataPlacemark.h" #include "GeoDataGeometry.h" #include "osm/OsmPlacemarkData.h" #include "osm/OsmObjectManager.h" #include "osm/OsmRelationEditorDialog.h" namespace Marble { OsmRelationManagerWidget::OsmRelationManagerWidget( GeoDataPlacemark *placemark, const QHash *relations, QWidget *parent ) : QWidget( parent ), d( new OsmRelationManagerWidgetPrivate ) { d->m_placemark = placemark; d->m_allRelations = relations; d->setupUi( this ); d->populateRelationsList(); d->m_relationDropMenu = new QMenu( d->m_addRelation ); d->m_currentRelations->setRootIsDecorated( false ); d->m_currentRelations->setEditTriggers( QTreeWidget::DoubleClicked ); d->m_currentRelations->setContextMenuPolicy( Qt::CustomContextMenu ); d->m_currentRelations->setMinimumWidth( d->m_currentRelations->columnCount() * d->m_currentRelations->columnWidth( 0 ) + 10 ); d->m_addRelation->setMenu( d->m_relationDropMenu ); d->populateDropMenu(); QObject::connect( d->m_currentRelations, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( handleDoubleClick(QTreeWidgetItem*,int) ) ); QObject::connect( d->m_currentRelations, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( handleRelationContextMenuRequest( QPoint ) ) ); QObject::connect( d->m_relationDropMenu, SIGNAL( triggered( QAction* ) ), this, SLOT( addRelation( QAction* ) ) ); QObject::connect( d->m_currentRelations, SIGNAL( itemChanged(QTreeWidgetItem*,int) ), this, SLOT( handleItemChange( QTreeWidgetItem*,int ) ) ); } OsmRelationManagerWidget::~OsmRelationManagerWidget() { delete d; } void OsmRelationManagerWidget::addRelation( QAction *relationAction ) { // The QAction::text() adds a '&' for some reason QString relationText = relationAction->text().remove(QLatin1Char('&')); if ( relationText == tr( "New Relation" ) ) { OsmPlacemarkData relationData; QPointer relationEditor = new OsmRelationEditorDialog( &relationData ); const int result = relationEditor->exec(); delete relationEditor; if (result == QDialog::Rejected) { return; } QTreeWidgetItem *newRelationItem = new QTreeWidgetItem(); newRelationItem->setText(Column::Name, relationData.tagValue(QStringLiteral("name"))); newRelationItem->setText(Column::Type, relationData.tagValue(QStringLiteral("type"))); newRelationItem->setData( Column::Name, Qt::UserRole, relationData.id() ); d->m_currentRelations->addTopLevelItem( newRelationItem ); // Make the user complete the role column newRelationItem->setFlags( newRelationItem->flags() | Qt::ItemIsEditable ); d->m_currentRelations->editItem( newRelationItem, Column::Role ); // This tells the annotate plugin to add the new relation to its list emit relationCreated( relationData ); } else { qint64 id = relationAction->data().toLongLong(); OsmPlacemarkData relationData = d->m_allRelations->value( id ); QTreeWidgetItem *newRelationItem = new QTreeWidgetItem(); newRelationItem->setText(Column::Name, relationData.tagValue(QStringLiteral("name"))); newRelationItem->setText(Column::Type, relationData.tagValue(QStringLiteral("type"))); newRelationItem->setData( Column::Name, Qt::UserRole, relationData.id() ); d->m_currentRelations->addTopLevelItem( newRelationItem ); // Make the user complete the role column newRelationItem->setFlags( newRelationItem->flags() | Qt::ItemIsEditable ); d->m_currentRelations->editItem( newRelationItem, Column::Role ); } } void OsmRelationManagerWidget::update() { d->populateRelationsList(); d->populateDropMenu(); } void OsmRelationManagerWidget::handleDoubleClick( QTreeWidgetItem * item, int column ) { Qt::ItemFlags flags = item->flags(); // Only the "role" column should be editable if ( column == Column::Role ) { item->setFlags( flags | Qt::ItemIsEditable ); // If the double click didn't occur on the "role" column, and the item // is editable make it uneditable } else if ( flags & Qt::ItemIsEditable ) { item->setFlags( flags ^ Qt::ItemIsEditable ); } } void OsmRelationManagerWidget::handleItemChange( QTreeWidgetItem *item, int column ) { // Only the role column should be editable if ( column != Column::Role ) { return; } QString role = item->text( Column::Role ); qint64 id = item->data( Column::Name, Qt::UserRole ).toLongLong(); d->m_placemark->osmData().addRelation( id, role ); update(); } void OsmRelationManagerWidget::handleRelationContextMenuRequest( const QPoint& point ) { QMenu relationEditMenu; relationEditMenu.addAction( tr( "Remove" ) ); relationEditMenu.addAction( tr( "Edit" ) ); QAction* selectedItem = relationEditMenu.exec( d->m_currentRelations->mapToGlobal( point ) ); if ( selectedItem ) { QTreeWidgetItem *requestedItem = d->m_currentRelations->itemAt( point ); qint64 id = requestedItem->data( Column::Name, Qt::UserRole ).toLongLong(); if ( selectedItem->text() == tr( "Remove" ) ) { d->m_placemark->osmData().removeRelation( id ); update(); } else if ( selectedItem->text() == tr( "Edit" ) ) { OsmPlacemarkData relationData = d->m_allRelations->value( id ); QPointer relationEditor = new OsmRelationEditorDialog( &relationData ); const int result = relationEditor->exec(); delete relationEditor; if (result == QDialog::Rejected) { return; } emit relationCreated( relationData ); update(); } } } } #include "moc_OsmRelationManagerWidget.cpp" diff --git a/src/lib/marble/osm/OsmRelationManagerWidget_p.cpp b/src/lib/marble/osm/OsmRelationManagerWidget_p.cpp index 03be8894a..757a4afd0 100644 --- a/src/lib/marble/osm/OsmRelationManagerWidget_p.cpp +++ b/src/lib/marble/osm/OsmRelationManagerWidget_p.cpp @@ -1,104 +1,103 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Stanciu Marius-Valeriu // // Self #include "OsmRelationManagerWidget_p.h" #include "OsmRelationManagerWidget.h" // Marble #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" #include "GeoDataStyle.h" #include "OsmPlacemarkData.h" #include "MarbleDebug.h" // Qt #include #include namespace Marble { OsmRelationManagerWidgetPrivate::OsmRelationManagerWidgetPrivate() { // nothing to do } OsmRelationManagerWidgetPrivate::~OsmRelationManagerWidgetPrivate() { // nothing to do } void OsmRelationManagerWidgetPrivate::populateRelationsList() { m_currentRelations->clear(); // This shouldn't happen if ( !m_allRelations ) { return; } if ( m_placemark->hasOsmData() ) { const OsmPlacemarkData &osmData = m_placemark->osmData(); QHash< qint64, QString >::const_iterator it = osmData.relationReferencesBegin(); QHash< qint64, QString >::const_iterator end = osmData.relationReferencesEnd(); for ( ; it != end; ++it ) { if ( !m_allRelations->contains( it.key() ) ) { mDebug()<< QString( "Relation %1 is not loaded in the Annotate Plugin" ).arg( it.key() ); continue; } const OsmPlacemarkData &relationData = m_allRelations->value( it.key() ); QTreeWidgetItem *newItem = new QTreeWidgetItem(); QString name = relationData.tagValue(QStringLiteral("name")); QString type = relationData.tagValue(QStringLiteral("type")); QString role = it.value(); newItem->setText( Column::Name, name ); newItem->setText( Column::Type, type ); newItem->setText( Column::Role, role ); newItem->setData( Column::Name, Qt::UserRole, relationData.id() ); m_currentRelations->addTopLevelItem( newItem ); } } } void OsmRelationManagerWidgetPrivate::populateDropMenu() { m_relationDropMenu->clear(); m_addRelation->setIcon(QIcon(QStringLiteral(":marble/list-add.png"))); // The new relation adder m_relationDropMenu->addAction( QObject::tr( "New Relation" ) ); m_relationDropMenu->addSeparator(); // This shouldn't happen Q_ASSERT( m_allRelations ); // Suggesting existing relations for ( const OsmPlacemarkData &relationData: m_allRelations->values() ) { const QString relationText = relationData.tagValue("name") + QLatin1String(" (") + relationData.tagValue("type") + QLatin1Char(')'); // Don't suggest relations the placemark is already part of if ( m_placemark->hasOsmData() && m_placemark->osmData().containsRelation( relationData.id() ) ) { continue; } QAction *newAction = new QAction( m_relationDropMenu ); newAction->setText( relationText ); newAction->setData( relationData.id() ); m_relationDropMenu->addAction( newAction ); } } } diff --git a/src/lib/marble/osm/OsmTagEditorWidget.cpp b/src/lib/marble/osm/OsmTagEditorWidget.cpp index e3786da2e..bf2d4b45e 100644 --- a/src/lib/marble/osm/OsmTagEditorWidget.cpp +++ b/src/lib/marble/osm/OsmTagEditorWidget.cpp @@ -1,174 +1,173 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Stanciu Marius-Valeriu // // Self #include "OsmTagEditorWidget.h" #include "OsmTagEditorWidget_p.h" #include "ui_OsmTagEditorWidget.h" // Qt #include #include #include // Marble -#include "GeoDataTypes.h" #include "GeoDataPlacemark.h" #include "GeoDataGeometry.h" #include "OsmPlacemarkData.h" namespace Marble { OsmTagEditorWidget::OsmTagEditorWidget( GeoDataPlacemark *placemark, QWidget *parent ) : QWidget( parent ), d( new OsmTagEditorWidgetPrivate ) { d->m_placemark = placemark; d->setupUi( this ); d->populatePresetTagsList(); d->populateCurrentTagsList(); d->m_recommendedTagsList->setSelectionBehavior( QAbstractItemView::SelectRows ); d->m_recommendedTagsList->setSelectionMode( QAbstractItemView::SingleSelection ); d->m_recommendedTagsList->setRootIsDecorated( false ); d->m_currentTagsList->setSelectionBehavior( QAbstractItemView::SelectRows ); d->m_currentTagsList->setSelectionMode( QAbstractItemView::SingleSelection ); d->m_currentTagsList->setRootIsDecorated( false ); QObject::connect( d->m_addTagButton, SIGNAL( pressed() ), this, SLOT( addSelectedTag() ) ); QObject::connect( d->m_recommendedTagsList, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( addSelectedTag() ) ); QObject::connect( d->m_removeTagButton, SIGNAL( pressed() ), this, SLOT( removeSelectedTag() ) ); QObject::connect( d->m_currentTagsList, SIGNAL( itemChanged( QTreeWidgetItem*, int ) ), this, SLOT( handleItemChanged( QTreeWidgetItem*, int ) ) ); QObject::connect( d->m_currentTagsList, SIGNAL( itemDoubleClicked(QTreeWidgetItem*,int) ), this, SLOT( handleDoubleClick( QTreeWidgetItem*, int) ) ); } OsmTagEditorWidget::~OsmTagEditorWidget() { delete d; } void OsmTagEditorWidget::update() { d->m_currentTagsList->clear(); d->m_recommendedTagsList->clear(); d->populatePresetTagsList(); d->populateCurrentTagsList(); emit placemarkChanged( d->m_placemark ); } OsmPlacemarkData OsmTagEditorWidget::placemarkData() const { OsmPlacemarkData osmData; for (int index = 0; index < d->m_currentTagsList->topLevelItemCount(); ++index) { const QTreeWidgetItem *item = d->m_currentTagsList->topLevelItem( index ); osmData.addTag(item->text(0), item->text(1)); } return osmData; } void OsmTagEditorWidget::addSelectedTag() { QTreeWidgetItem *selectedTag = d->m_recommendedTagsList->currentItem(); if ( !selectedTag ) { return; } // Adding the tag to the placemark's osmData QString key = selectedTag->text( 0 ); QString value = selectedTag->text( 1 ); // If the value is , the user has to type a value for that particular key if (value == QLatin1Char('<') + tr("value") + QLatin1Char('>')) { int lastIndex = d->m_currentTagsList->topLevelItemCount() - 1; QTreeWidgetItem *adderItem = d->m_currentTagsList->topLevelItem( lastIndex ); adderItem->setText( 0, key ); d->m_currentTagsList->editItem( adderItem, 1 ); d->m_currentTagsList->setCurrentItem( adderItem ); } else { d->m_placemark->osmData().addTag( key, value ); QTreeWidgetItem *newItem = d->tagWidgetItem( OsmTagEditorWidgetPrivate::OsmTag( key, value ) ); newItem->setFlags( newItem->flags() | Qt::ItemIsUserCheckable ); newItem->setCheckState( 0, Qt::Unchecked ); d->m_currentTagsList->addTopLevelItem( newItem ); update(); } } void OsmTagEditorWidget::removeSelectedTag() { QTreeWidgetItem *selectedTag = d->m_currentTagsList->currentItem(); if ( !selectedTag ) { return; } // Adding the tag to the placemark's osmData QString key = selectedTag->text( 0 ); d->m_placemark->osmData().removeTag( key ); update(); } void OsmTagEditorWidget::handleItemChanged( QTreeWidgetItem *item, int column ) { Q_UNUSED( column ); QString key = item->text( 0 ); QString value = item->text( 1 ); // If any of the fields is still empty ( or the first field is "Add custom tag..." // the editing is not yet finished. if ( key.isEmpty() || value.isEmpty() || key == d->m_customTagAdderText ) { return; } d->m_placemark->osmData().addTag( key, value ); update(); } void OsmTagEditorWidget::handleDoubleClick( QTreeWidgetItem *item, int column ) { Q_UNUSED( column ); int index = d->m_currentTagsList->indexOfTopLevelItem( item ); int lastIndex = d->m_currentTagsList->topLevelItemCount() - 1; // The user double-clicked on the "Add custom tag..." element, so the text is cleared if ( index == lastIndex ) { QString key = item->text( 0 ); if ( key == d->m_customTagAdderText ) { item->setText( 0, QString() ); } } // The user double-clicked on a valid tag, so the tag is removed else if ( !item->isDisabled() ) { d->m_placemark->osmData().removeTag( item->text( 0 ) ); update(); } } } #include "moc_OsmTagEditorWidget.cpp" diff --git a/src/lib/marble/osm/OsmTagEditorWidget_p.cpp b/src/lib/marble/osm/OsmTagEditorWidget_p.cpp index e41a3f7d7..3c7fb9893 100644 --- a/src/lib/marble/osm/OsmTagEditorWidget_p.cpp +++ b/src/lib/marble/osm/OsmTagEditorWidget_p.cpp @@ -1,473 +1,451 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Stanciu Marius-Valeriu // // Self #include "OsmTagEditorWidget_p.h" #include "OsmTagEditorWidget.h" // Marble +#include "GeoDataLineString.h" +#include "GeoDataPolygon.h" #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include "OsmPlacemarkData.h" #include "GeoDataExtendedData.h" #include "GeoDataData.h" #include "GeoDataGeometry.h" +#include "GeoDataPoint.h" #include "StyleBuilder.h" // Qt #include #include namespace Marble { const QString OsmTagEditorWidgetPrivate::m_customTagAdderText = QObject::tr( "Add custom tag..." ); OsmTagEditorWidgetPrivate::OsmTagEditorWidgetPrivate() { // nothing to do } OsmTagEditorWidgetPrivate::~OsmTagEditorWidgetPrivate() { // nothing to do } void OsmTagEditorWidgetPrivate::populateCurrentTagsList() { // Name tag if ( !m_placemark->name().isEmpty() ) { QStringList itemText; // "name" is a standard OSM tag, don't translate itemText<< "name" << m_placemark->name(); QTreeWidgetItem *nameTag = new QTreeWidgetItem( itemText ); nameTag->setDisabled( true ); m_currentTagsList->addTopLevelItem( nameTag ); } // Multipolygon type tag - if ( m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { + if (geodata_cast(m_placemark->geometry())) { QStringList itemText; // "type" is a standard OSM tag, don't translate itemText<< "type" << "multipolygon"; QTreeWidgetItem *typeTag = new QTreeWidgetItem( itemText ); typeTag->setDisabled( true ); m_currentTagsList->addTopLevelItem( typeTag ); } // Other tags if( m_placemark->hasOsmData() ) { const OsmPlacemarkData& osmData = m_placemark->osmData(); QHash< QString, QString>::const_iterator it = osmData.tagsBegin(); QHash< QString, QString>::const_iterator end = osmData.tagsEnd(); for ( ; it != end; ++it ) { QTreeWidgetItem *tagItem = tagWidgetItem(OsmTag(it.key(), it.value())); m_currentTagsList->addTopLevelItem( tagItem ); } } // Custom tag adder item QTreeWidgetItem *adderItem = new QTreeWidgetItem(); adderItem->setText( 0, m_customTagAdderText ); adderItem->setTextColor( 0, Qt::gray ); adderItem->setIcon(0, QIcon(QStringLiteral(":marble/list-add.png"))); adderItem->setFlags( adderItem->flags() | Qt::ItemIsEditable ); m_currentTagsList->addTopLevelItem( adderItem ); m_currentTagsList->resizeColumnToContents( 0 ); m_currentTagsList->resizeColumnToContents( 1 ); } void OsmTagEditorWidgetPrivate::populatePresetTagsList() { QList tags = recommendedTags(); for (const OsmTag &tag: tags) { QTreeWidgetItem *tagItem = tagWidgetItem( tag ); m_recommendedTagsList->addTopLevelItem( tagItem ); } } QTreeWidgetItem *OsmTagEditorWidgetPrivate::tagWidgetItem( const OsmTag &tag ) const { QStringList itemText; itemText << tag.first; itemText << (tag.second.isEmpty() ? QLatin1Char('<') + QObject::tr("value") + QLatin1Char('>') : tag.second); QTreeWidgetItem *tagItem = new QTreeWidgetItem( itemText ); return tagItem; } QList OsmTagEditorWidgetPrivate::recommendedTags() const { static const QVector additionalOsmTags = createAdditionalOsmTags(); QList recommendedTags; QStringList filter = generateTagFilter(); auto const osmTagMapping = StyleBuilder::osmTagMapping(); for (auto iter=osmTagMapping.begin(), end=osmTagMapping.end() ; iter != end; ++iter) { if ( filter.contains( iter.key().first ) ) { recommendedTags += iter.key(); } } for (const auto additionalOsmTag: additionalOsmTags) { if (filter.contains(additionalOsmTag.first)) { recommendedTags += additionalOsmTag; } } return recommendedTags; } QStringList OsmTagEditorWidgetPrivate::generateTagFilter() const { // TO DO: implement more dynamic criteria for the filter // based on https://taginfo.openstreetmap.org/ and http://wiki.openstreetmap.org/wiki/ // Contains all keys that should pass through the filter ( eg. { "amenity", "landuse", etc.. } ) QStringList filter; - bool condition; QStringList tags, tagsAux; - QString type; - if (m_placemark->extendedData().value(QStringLiteral("osmRelation")).value().toString() == QLatin1String("yes")) { - type = "Relation"; - } - else { - type = m_placemark->geometry()->nodeType(); - } OsmPlacemarkData osmData; if ( m_placemark->hasOsmData() ) { osmData = m_placemark->osmData(); } else { osmData = OsmPlacemarkData(); } // Patterns in order of usefulness // If the placemark is a node, and it doesn't already have any node-specific tags, recommend all node-specific tags tags = QStringList() << "amenity=*" << "shop=*" << "transport=*" << "tourism=*" << "historic=*" << "power=*" << "barrier=*"; - condition = ( type == GeoDataTypes::GeoDataPointType ) && !containsAny( osmData, tags ); - if ( condition ) { + if (geodata_cast(m_placemark->geometry()) && !containsAny(osmData, tags)) { addPattern( filter, osmData, tags ); } // If the placemark is a way, and it doesn't already have any way-specific tags, recommend all way-specific tags tags = QStringList() << "highway=*" << "waterway=*" << "railway=*"; - condition = ( type == GeoDataTypes::GeoDataLineStringType ) && !containsAny( osmData, tags ); - if ( condition ) { + if (geodata_cast(m_placemark->geometry()) && !containsAny(osmData, tags)) { addPattern( filter, osmData, tags ); } // If the placemark is a polygon, and it doesn't already have any polygon-specific tags, recommend all polygon-specific tags tags = QStringList() << "landuse=*" << "leisure=*"; - condition = ( type == GeoDataTypes::GeoDataPolygonType ) && !containsAny( osmData, tags ); - if ( condition ) { + if (geodata_cast(m_placemark->geometry()) && !containsAny(osmData, tags)) { addPattern( filter, osmData, tags ); } // If the placemark is a relation, recommend type=* tags = QStringList() << "type=*"; - condition = (type == QLatin1String("Relation")); - if ( condition ) { + if (m_placemark->extendedData().value(QStringLiteral("osmRelation")).value().toString() == QLatin1String("yes")) { addPattern( filter, osmData, tags ); } // If the placemark has type=route, recommend route=*, network=*, ref=*, operator=* tags = QStringList() << "type=route"; tagsAux = QStringList() << "route=*" << "network=*" << "ref=*" << "operator=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has type=route_master, recommend route_master=*, tags = QStringList() << "type=route_master"; tagsAux = QStringList() << "route_master=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has type=public_transport, recommend public_transport=*, tags = QStringList() << "type=public_transport"; tagsAux = QStringList() << "public_transport=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has type=waterway, recommend waterway=*, tags = QStringList() << "type=waterway"; tagsAux = QStringList() << "waterway=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has type=enforcement, recommend enforcement=*, tags = QStringList() << "type=enforcement"; tagsAux = QStringList() << "enforcement=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has amenity=place_of_worship, recommend religion=* tags = QStringList() << "amenity=place_of_worship"; tagsAux = QStringList() << "religion=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has amenity=toilets, recommend drinking_water=*, indoor=* tags = QStringList() << "amenity=toilets"; tagsAux = QStringList() << "drinking_water=*" << "indoor=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has tourism=hostel, tourism=hotel or tourism=motel, recommend rooms=*, beds=*, wheelchair=* tags = QStringList() << "tourism=hotel" << "tourism=hostel" << "tourism=motel"; tagsAux = QStringList() << "rooms=*" << "beds=*" << "wheelchair=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has tourism=*, shop=*, amenity=*, recommend website=*, email=*, fee=* tags = QStringList() << "tourism=*" << "shop=*" << "amenity=*"; tagsAux = QStringList() << "website=*" << "email=*" << "fee=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has amenity=* shop=*, recommend building=* tags = QStringList() << "amenity=*" << "shop=*"; tagsAux = QStringList() << "building=*"; - condition = containsAny( osmData, tags ); - if ( condition ) { + if (containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark has highway=*, recommend "lanes=*", "maxspeed=*", "oneway=*", "service=*", "bridge=*", "tunnel=*" tags = QStringList() << "highway=*"; tagsAux = QStringList() << "lanes=*" << "maxspeed=*" << "maxheight=*" << "maxweight=*" << "abutters=*" << "oneway=*" << "service=*" << "bridge=*" << "tunnel=*"; - condition = ( type == GeoDataTypes::GeoDataLineStringType ) && containsAny( osmData, tags ); - if ( condition ) { + if (geodata_cast(m_placemark->geometry()) && containsAny(osmData, tags)) { addPattern( filter, osmData, tagsAux ); } // If the placemark is a polygon, recommend "surface=*" tags = QStringList() << "surface=*"; - condition = ( type == GeoDataTypes::GeoDataPolygonType ); - if ( condition ) { + if (geodata_cast(m_placemark->geometry())) { addPattern( filter, osmData, tags ); } // Always recommend these: tags = QStringList() << "addr:street=*" << "addr:housenumber=*" << "addr:postcode=*" << "addr:country=*" << "access=*"; addPattern( filter, osmData, tags ); return filter; } bool OsmTagEditorWidgetPrivate::containsAny( const OsmPlacemarkData &osmData, const QStringList &tags ) const { for ( const QString &tag: tags ) { const QStringList tagSplit = tag.split(QLatin1Char('=')); // Only "key=value" mappings should be checked Q_ASSERT( tagSplit.size() == 2 ); QString key = tagSplit.at( 0 ); QString value = tagSplit.at( 1 ); if (value == QLatin1String("*") && osmData.containsTagKey(key)) { return true; } else if (value != QLatin1String("*") && osmData.containsTag(key, value)) { return true; } } return false; } void OsmTagEditorWidgetPrivate::addPattern( QStringList &filter, const OsmPlacemarkData &osmData, const QStringList &tags ) const { for ( const QString &tag: tags ) { const QStringList tagSplit = tag.split(QLatin1Char('=')); QString key = tagSplit.at( 0 ); if ( !osmData.containsTagKey( key ) ) { filter << key; } } } QVector OsmTagEditorWidgetPrivate::createAdditionalOsmTags() { const QVector additionalOsmTags = QVector() // Recommended for nodes << OsmTag("power", "pole") << OsmTag("power", "generator") << OsmTag("barrier", "fence") << OsmTag("barrier", "wall") << OsmTag("barrier", "gate") // Recommended for ways << OsmTag("lanes", "") << OsmTag("maxspeed", "") << OsmTag("maxheight", "") << OsmTag("maxweight", "") << OsmTag("oneway", "yes") << OsmTag("service", "driveway") << OsmTag("service", "parking_aisle") << OsmTag("service", "alley") << OsmTag("tunnel", "yes") << OsmTag("abutters", "commercial") << OsmTag("abutters", "industrial") << OsmTag("abutters", "mixed") << OsmTag("abutters", "residential") // Recommended for areas << OsmTag("surface", "unpaved") << OsmTag("surface", "paved") << OsmTag("surface", "gravel") << OsmTag("surface", "dirt") << OsmTag("surface", "grass") // Relations << OsmTag("type", "route") << OsmTag("type", "route_master") << OsmTag("type", "public_transport") << OsmTag("type", "destination_sign") << OsmTag("type", "waterway") << OsmTag("type", "enforcement") // Relations: route << OsmTag("route", "road") << OsmTag("route", "bicycle") << OsmTag("route", "foot") << OsmTag("route", "hiking") << OsmTag("route", "bus") << OsmTag("route", "trolleybus") << OsmTag("route", "ferry") << OsmTag("route", "detour") << OsmTag("route", "train") << OsmTag("route", "tram") << OsmTag("route", "mtb") << OsmTag("route", "horse") << OsmTag("route", "ski") << OsmTag("roundtrip", "yes") << OsmTag("network", "") << OsmTag("ref", "") << OsmTag("operator", "") // Relations: route_master << OsmTag("route_master", "train") << OsmTag("route_master", "subway") << OsmTag("route_master", "monorail") << OsmTag("route_master", "tram") << OsmTag("route_master", "bus") << OsmTag("route_master", "trolleybus") << OsmTag("route_master", "ferry") << OsmTag("route_master", "bicycle") // Relations: public_transport << OsmTag("public_transport", "stop_area") << OsmTag("public_transport", "stop_area_group") // Relations: waterway << OsmTag("waterway", "river") << OsmTag("waterway", "stream") << OsmTag("waterway", "canal") << OsmTag("waterway", "drain") << OsmTag("waterway", "ditch") // Relations: enforcement << OsmTag("enforcement", "maxheight") << OsmTag("enforcement", "maxweight") << OsmTag("enforcement", "maxspeed") << OsmTag("enforcement", "mindistance") << OsmTag("enforcement", "traffic_signals") << OsmTag("enforcement", "check") << OsmTag("enforcement", "access") << OsmTag("enforcement", "toll") // Others << OsmTag("height", "") << OsmTag("rooms", "") << OsmTag("beds", "") << OsmTag("wheelchair", "") << OsmTag("website", "") << OsmTag("email", "") << OsmTag("fee", "") << OsmTag("destination", "") << OsmTag("indoor", "yes") // Recommended for all << OsmTag("addr:street", "") << OsmTag("addr:housenumber", "") << OsmTag("addr:postcode", "") << OsmTag("addr:country", "") << OsmTag("access", "private") << OsmTag("access", "permissive"); return additionalOsmTags; } } diff --git a/src/lib/marble/routing/RoutingWidget.cpp b/src/lib/marble/routing/RoutingWidget.cpp index 6d40a3bb5..a533476bc 100644 --- a/src/lib/marble/routing/RoutingWidget.cpp +++ b/src/lib/marble/routing/RoutingWidget.cpp @@ -1,1033 +1,1032 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2010 Dennis Nienhüser // #include "RoutingWidget.h" #include "GeoDataLineString.h" #include "GeoDataLookAt.h" #include "GeoDataPlaylist.h" #include "GeoDataTour.h" #include "GeoDataFlyTo.h" #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include "GeoDataPlacemark.h" #include "TourPlayback.h" #include "Maneuver.h" #include "MarbleModel.h" #include "MarblePlacemarkModel.h" #include "MarbleWidget.h" #include "MarbleWidgetInputHandler.h" #include "Route.h" #include "RouteRequest.h" #include "RoutingInputWidget.h" #include "RoutingLayer.h" #include "RoutingManager.h" #include "RoutingModel.h" #include "RoutingProfilesModel.h" #include "RoutingProfileSettingsDialog.h" #include "GeoDataDocument.h" #include "GeoDataTreeModel.h" -#include "GeoDataTypes.h" #include "GeoDataCreate.h" #include "GeoDataUpdate.h" #include "GeoDataDelete.h" #include "AlternativeRoutesModel.h" #include "RouteSyncManager.h" #include "CloudRoutesDialog.h" #include "CloudSyncManager.h" #include "PlaybackAnimatedUpdateItem.h" #include "GeoDataAnimatedUpdate.h" #include "MarbleMath.h" #include "Planet.h" #include #include #include #include #include #include #include #include #include "ui_RoutingWidget.h" namespace Marble { struct WaypointInfo { int index; double distance; // distance to route start GeoDataCoordinates coordinates; Maneuver maneuver; QString info; WaypointInfo( int index_, double distance_, const GeoDataCoordinates &coordinates_, Maneuver maneuver_, const QString& info_ ) : index( index_ ), distance( distance_ ), coordinates( coordinates_ ), maneuver( maneuver_ ), info( info_ ) { // nothing to do } }; class RoutingWidgetPrivate { public: Ui::RoutingWidget m_ui; MarbleWidget *const m_widget; RoutingManager *const m_routingManager; RoutingLayer *const m_routingLayer; RoutingInputWidget *m_activeInput; QVector m_inputWidgets; RoutingInputWidget *m_inputRequest; QAbstractItemModel *const m_routingModel; RouteRequest *const m_routeRequest; RouteSyncManager *m_routeSyncManager; bool m_zoomRouteAfterDownload; QTimer m_progressTimer; QVector m_progressAnimation; GeoDataDocument *m_document; GeoDataTour *m_tour; TourPlayback *m_playback; int m_currentFrame; int m_iconSize; int m_collapse_width; bool m_playing; QString m_planetId; QToolBar *m_toolBar; QToolButton *m_openRouteButton; QToolButton *m_saveRouteButton; QAction *m_cloudSyncSeparator; QAction *m_uploadToCloudAction; QAction *m_openCloudRoutesAction; QToolButton *m_addViaButton; QToolButton *m_reverseRouteButton; QToolButton *m_clearRouteButton; QToolButton *m_configureButton; QToolButton *m_playButton; QProgressDialog* m_routeUploadDialog; /** Constructor */ RoutingWidgetPrivate(RoutingWidget *parent, MarbleWidget *marbleWidget ); /** * @brief Toggle between simple search view and route view * If only one input field exists, hide all buttons */ void adjustInputWidgets(); void adjustSearchButton(); /** * @brief Change the active input widget * The active input widget influences what is shown in the paint layer * and in the list view: Either a set of placemarks that correspond to * a runner search result or the current route */ void setActiveInput( RoutingInputWidget* widget ); void setupToolBar(); private: void createProgressAnimation(); RoutingWidget *m_parent; }; RoutingWidgetPrivate::RoutingWidgetPrivate( RoutingWidget *parent, MarbleWidget *marbleWidget ) : m_widget( marbleWidget ), m_routingManager( marbleWidget->model()->routingManager() ), m_routingLayer( marbleWidget->routingLayer() ), m_activeInput( 0 ), m_inputRequest( 0 ), m_routingModel( m_routingManager->routingModel() ), m_routeRequest( marbleWidget->model()->routingManager()->routeRequest() ), m_routeSyncManager( 0 ), m_zoomRouteAfterDownload( false ), m_document( 0 ), m_tour( 0 ), m_playback( 0 ), m_currentFrame( 0 ), m_iconSize( 16 ), m_collapse_width( 0 ), m_playing( false ), m_planetId(marbleWidget->model()->planetId()), m_toolBar( 0 ), m_openRouteButton( 0 ), m_saveRouteButton( 0 ), m_cloudSyncSeparator( 0 ), m_uploadToCloudAction( 0 ), m_openCloudRoutesAction( 0 ), m_addViaButton( 0 ), m_reverseRouteButton( 0 ), m_clearRouteButton( 0 ), m_configureButton( 0 ), m_routeUploadDialog( 0 ), m_parent( parent ) { createProgressAnimation(); m_progressTimer.setInterval( 100 ); if ( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ) { m_iconSize = 32; } } void RoutingWidgetPrivate::adjustInputWidgets() { for ( int i = 0; i < m_inputWidgets.size(); ++i ) { m_inputWidgets[i]->setIndex( i ); } adjustSearchButton(); } void RoutingWidgetPrivate::adjustSearchButton() { QString text = QObject::tr( "Get Directions" ); QString tooltip = QObject::tr( "Retrieve routing instructions for the selected destinations." ); int validInputs = 0; for ( int i = 0; i < m_inputWidgets.size(); ++i ) { if ( m_inputWidgets[i]->hasTargetPosition() ) { ++validInputs; } } if ( validInputs < 2 ) { text = QObject::tr( "Search" ); tooltip = QObject::tr( "Find places matching the search term" ); } m_ui.searchButton->setText( text ); m_ui.searchButton->setToolTip( tooltip ); } void RoutingWidgetPrivate::setActiveInput( RoutingInputWidget *widget ) { Q_ASSERT( widget && "Must not pass null" ); MarblePlacemarkModel *model = widget->searchResultModel(); m_activeInput = widget; m_ui.directionsListView->setModel( model ); m_routingLayer->setPlacemarkModel( model ); m_routingLayer->synchronizeWith( m_ui.directionsListView->selectionModel() ); } void RoutingWidgetPrivate::setupToolBar() { m_toolBar = new QToolBar; m_openRouteButton = new QToolButton; m_openRouteButton->setToolTip( QObject::tr("Open Route") ); m_openRouteButton->setIcon(QIcon(QStringLiteral(":/icons/16x16/document-open.png"))); m_toolBar->addWidget(m_openRouteButton); m_saveRouteButton = new QToolButton; m_saveRouteButton->setToolTip( QObject::tr("Save Route") ); m_saveRouteButton->setIcon(QIcon(QStringLiteral(":/icons/16x16/document-save.png"))); m_toolBar->addWidget(m_saveRouteButton); m_playButton = new QToolButton; m_playButton->setToolTip( QObject::tr("Preview Route") ); m_playButton->setIcon(QIcon(QStringLiteral(":/marble/playback-play.png"))); m_toolBar->addWidget(m_playButton); m_cloudSyncSeparator = m_toolBar->addSeparator(); m_uploadToCloudAction = m_toolBar->addAction( QObject::tr("Upload to Cloud") ); m_uploadToCloudAction->setToolTip( QObject::tr("Upload to Cloud") ); m_uploadToCloudAction->setIcon(QIcon(QStringLiteral(":/icons/cloud-upload.png"))); m_openCloudRoutesAction = m_toolBar->addAction( QObject::tr("Manage Cloud Routes") ); m_openCloudRoutesAction->setToolTip( QObject::tr("Manage Cloud Routes") ); m_openCloudRoutesAction->setIcon(QIcon(QStringLiteral(":/icons/cloud-download.png"))); m_toolBar->addSeparator(); m_addViaButton = new QToolButton; m_addViaButton->setToolTip( QObject::tr("Add Via") ); m_addViaButton->setIcon(QIcon(QStringLiteral(":/marble/list-add.png"))); m_toolBar->addWidget(m_addViaButton); m_reverseRouteButton = new QToolButton; m_reverseRouteButton->setToolTip( QObject::tr("Reverse Route") ); m_reverseRouteButton->setIcon(QIcon(QStringLiteral(":/marble/reverse.png"))); m_toolBar->addWidget(m_reverseRouteButton); m_clearRouteButton = new QToolButton; m_clearRouteButton->setToolTip( QObject::tr("Clear Route") ); m_clearRouteButton->setIcon(QIcon(QStringLiteral(":/marble/edit-clear.png"))); m_toolBar->addWidget(m_clearRouteButton); m_toolBar->addSeparator(); m_configureButton = new QToolButton; m_configureButton->setToolTip( QObject::tr("Settings") ); m_configureButton->setIcon(QIcon(QStringLiteral(":/icons/16x16/configure.png"))); m_toolBar->addWidget(m_configureButton); QObject::connect( m_openRouteButton, SIGNAL(clicked()), m_parent, SLOT(openRoute()) ); QObject::connect( m_saveRouteButton, SIGNAL(clicked()), m_parent, SLOT(saveRoute()) ); QObject::connect( m_uploadToCloudAction, SIGNAL(triggered()), m_parent, SLOT(uploadToCloud()) ); QObject::connect( m_openCloudRoutesAction, SIGNAL(triggered()), m_parent, SLOT(openCloudRoutesDialog())); QObject::connect( m_addViaButton, SIGNAL(clicked()), m_parent, SLOT(addInputWidget()) ); QObject::connect( m_reverseRouteButton, SIGNAL(clicked()), m_routingManager, SLOT(reverseRoute()) ); QObject::connect( m_clearRouteButton, SIGNAL(clicked()), m_routingManager, SLOT(clearRoute()) ); QObject::connect( m_configureButton, SIGNAL(clicked()), m_parent, SLOT(configureProfile()) ); QObject::connect( m_playButton, SIGNAL(clicked()), m_parent, SLOT(toggleRoutePlay()) ); m_toolBar->setIconSize(QSize(16, 16)); m_ui.toolBarLayout->addWidget(m_toolBar, 0, Qt::AlignLeft); } void RoutingWidgetPrivate::createProgressAnimation() { // Size parameters qreal const h = m_iconSize / 2.0; // Half of the icon size qreal const q = h / 2.0; // Quarter of the icon size qreal const d = 7.5; // Circle diameter qreal const r = d / 2.0; // Circle radius // Canvas parameters QImage canvas( m_iconSize, m_iconSize, QImage::Format_ARGB32 ); QPainter painter( &canvas ); painter.setRenderHint( QPainter::Antialiasing, true ); painter.setPen( QColor ( Qt::gray ) ); painter.setBrush( QColor( Qt::white ) ); // Create all frames for( double t = 0.0; t < 2 * M_PI; t += M_PI / 8.0 ) { canvas.fill( Qt::transparent ); QRectF firstCircle( h - r + q * cos( t ), h - r + q * sin( t ), d, d ); QRectF secondCircle( h - r + q * cos( t + M_PI ), h - r + q * sin( t + M_PI ), d, d ); painter.drawEllipse( firstCircle ); painter.drawEllipse( secondCircle ); m_progressAnimation.push_back( QIcon( QPixmap::fromImage( canvas ) ) ); } } RoutingWidget::RoutingWidget( MarbleWidget *marbleWidget, QWidget *parent ) : QWidget( parent ), d( new RoutingWidgetPrivate( this, marbleWidget ) ) { d->m_ui.setupUi( this ); d->setupToolBar(); d->m_ui.routeComboBox->setVisible( false ); d->m_ui.routeComboBox->setModel( d->m_routingManager->alternativeRoutesModel() ); layout()->setMargin( 0 ); d->m_ui.routingProfileComboBox->setModel( d->m_routingManager->profilesModel() ); connect( d->m_routingManager->profilesModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(selectFirstProfile()) ); connect( d->m_routingManager->profilesModel(), SIGNAL(modelReset()), this, SLOT(selectFirstProfile()) ); connect( d->m_routingLayer, SIGNAL(placemarkSelected(QModelIndex)), this, SLOT(activatePlacemark(QModelIndex)) ); connect( d->m_routingManager, SIGNAL(stateChanged(RoutingManager::State)), this, SLOT(updateRouteState(RoutingManager::State)) ); connect( d->m_routeRequest, SIGNAL(positionAdded(int)), this, SLOT(insertInputWidget(int)) ); connect( d->m_routeRequest, SIGNAL(positionRemoved(int)), this, SLOT(removeInputWidget(int)) ); connect( d->m_routeRequest, SIGNAL(routingProfileChanged()), this, SLOT(updateActiveRoutingProfile()) ); connect( &d->m_progressTimer, SIGNAL(timeout()), this, SLOT(updateProgress()) ); connect( d->m_ui.routeComboBox, SIGNAL(currentIndexChanged(int)), d->m_routingManager->alternativeRoutesModel(), SLOT(setCurrentRoute(int)) ); connect( d->m_routingManager->alternativeRoutesModel(), SIGNAL(currentRouteChanged(int)), d->m_ui.routeComboBox, SLOT(setCurrentIndex(int)) ); connect( d->m_ui.routingProfileComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setRoutingProfile(int)) ); connect( d->m_ui.routingProfileComboBox, SIGNAL(activated(int)), this, SLOT(retrieveRoute()) ); connect( d->m_routingManager->alternativeRoutesModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(updateAlternativeRoutes()) ); d->m_ui.directionsListView->setModel( d->m_routingModel ); QItemSelectionModel *selectionModel = d->m_ui.directionsListView->selectionModel(); d->m_routingLayer->synchronizeWith( selectionModel ); connect( d->m_ui.directionsListView, SIGNAL(activated(QModelIndex)), this, SLOT(activateItem(QModelIndex)) ); // FIXME: apply for this sector connect( d->m_ui.searchButton, SIGNAL(clicked()), this, SLOT(retrieveRoute()) ); connect( d->m_ui.showInstructionsButton, SIGNAL(clicked(bool)), this, SLOT(showDirections()) ); for( int i=0; im_routeRequest->size(); ++i ) { insertInputWidget( i ); } for ( int i=0; i<2 && d->m_inputWidgets.size()<2; ++i ) { // Start with source and destination if the route is empty yet addInputWidget(); } //d->m_ui.descriptionLabel->setVisible( false ); d->m_ui.resultLabel->setVisible( false ); setShowDirectionsButtonVisible( false ); updateActiveRoutingProfile(); updateCloudSyncButtons(); if ( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ) { d->m_ui.directionsListView->setVisible( false ); d->m_openRouteButton->setVisible( false ); d->m_saveRouteButton->setVisible( false ); } connect( marbleWidget->model(), SIGNAL(themeChanged(QString)), this, SLOT(handlePlanetChange()) ); } RoutingWidget::~RoutingWidget() { delete d->m_playback; delete d->m_tour; if( d->m_document ){ d->m_widget->model()->treeModel()->removeDocument( d->m_document ); delete d->m_document; } delete d; } void RoutingWidget::retrieveRoute() { if ( d->m_inputWidgets.size() == 1 ) { // Search mode d->m_inputWidgets.first()->findPlacemarks(); return; } int index = d->m_ui.routingProfileComboBox->currentIndex(); if ( index == -1 ) { return; } d->m_routeRequest->setRoutingProfile( d->m_routingManager->profilesModel()->profiles().at( index ) ); Q_ASSERT( d->m_routeRequest->size() == d->m_inputWidgets.size() ); for ( int i = 0; i < d->m_inputWidgets.size(); ++i ) { RoutingInputWidget *widget = d->m_inputWidgets.at( i ); if ( !widget->hasTargetPosition() && widget->hasInput() ) { widget->findPlacemarks(); return; } } d->m_activeInput = 0; if ( d->m_routeRequest->size() > 1 ) { d->m_zoomRouteAfterDownload = true; d->m_routingLayer->setPlacemarkModel( 0 ); d->m_routingManager->retrieveRoute(); d->m_ui.directionsListView->setModel( d->m_routingModel ); d->m_routingLayer->synchronizeWith( d->m_ui.directionsListView->selectionModel() ); } if( d->m_playback ) { d->m_playback->stop(); } } void RoutingWidget::activateItem ( const QModelIndex &index ) { QVariant data = index.data( MarblePlacemarkModel::CoordinateRole ); if ( !data.isNull() ) { GeoDataCoordinates position = qvariant_cast( data ); d->m_widget->centerOn( position, true ); } if ( d->m_activeInput && index.isValid() ) { QVariant data = index.data( MarblePlacemarkModel::CoordinateRole ); if ( !data.isNull() ) { d->m_activeInput->setTargetPosition( data.value(), index.data().toString() ); } } } void RoutingWidget::handleSearchResult( RoutingInputWidget *widget ) { d->setActiveInput( widget ); MarblePlacemarkModel *model = widget->searchResultModel(); if ( model->rowCount() ) { QString const results = tr( "placemarks found: %1" ).arg( model->rowCount() ); d->m_ui.resultLabel->setText( results ); d->m_ui.resultLabel->setVisible( true ); // Make sure we have a selection activatePlacemark( model->index( 0, 0 ) ); } else { QString const results = tr( "No placemark found" ); d->m_ui.resultLabel->setText(QLatin1String("") + results + QLatin1String("")); d->m_ui.resultLabel->setVisible( true ); } GeoDataLineString placemarks; for ( int i = 0; i < model->rowCount(); ++i ) { QVariant data = model->index( i, 0 ).data( MarblePlacemarkModel::CoordinateRole ); if ( !data.isNull() ) { placemarks << data.value(); } } if ( placemarks.size() > 1 ) { d->m_widget->centerOn( GeoDataLatLonBox::fromLineString( placemarks ) ); //d->m_ui.descriptionLabel->setVisible( false ); if ( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ) { d->m_ui.directionsListView->setVisible( true ); } } } void RoutingWidget::centerOnInputWidget( RoutingInputWidget *widget ) { if ( widget->hasTargetPosition() ) { d->m_widget->centerOn( widget->targetPosition() ); } } void RoutingWidget::activatePlacemark( const QModelIndex &index ) { if ( d->m_activeInput && index.isValid() ) { QVariant data = index.data( MarblePlacemarkModel::CoordinateRole ); if ( !data.isNull() ) { d->m_activeInput->setTargetPosition( data.value() ); } } d->m_ui.directionsListView->setCurrentIndex( index ); } void RoutingWidget::addInputWidget() { d->m_routeRequest->append( GeoDataCoordinates() ); } void RoutingWidget::insertInputWidget( int index ) { if ( index >= 0 && index <= d->m_inputWidgets.size() ) { RoutingInputWidget *input = new RoutingInputWidget( d->m_widget->model(), index, this ); d->m_inputWidgets.insert( index, input ); connect( input, SIGNAL(searchFinished(RoutingInputWidget*)), this, SLOT(handleSearchResult(RoutingInputWidget*)) ); connect( input, SIGNAL(removalRequest(RoutingInputWidget*)), this, SLOT(removeInputWidget(RoutingInputWidget*)) ); connect( input, SIGNAL(activityRequest(RoutingInputWidget*)), this, SLOT(centerOnInputWidget(RoutingInputWidget*)) ); connect( input, SIGNAL(mapInputModeEnabled(RoutingInputWidget*,bool)), this, SLOT(requestMapPosition(RoutingInputWidget*,bool)) ); connect( input, SIGNAL(targetValidityChanged(bool)), this, SLOT(adjustSearchButton()) ); d->m_ui.inputLayout->insertWidget( index, input ); d->adjustInputWidgets(); } } void RoutingWidget::removeInputWidget( RoutingInputWidget *widget ) { int index = d->m_inputWidgets.indexOf( widget ); if ( index >= 0 ) { if ( d->m_inputWidgets.size() < 3 ) { widget->clear(); } else { d->m_routeRequest->remove( index ); } d->m_routingManager->retrieveRoute(); } } void RoutingWidget::removeInputWidget( int index ) { if ( index >= 0 && index < d->m_inputWidgets.size() ) { RoutingInputWidget *widget = d->m_inputWidgets.at( index ); d->m_inputWidgets.remove( index ); d->m_ui.inputLayout->removeWidget( widget ); widget->deleteLater(); if ( widget == d->m_activeInput ) { d->m_activeInput = 0; d->m_routingLayer->setPlacemarkModel( 0 ); d->m_ui.directionsListView->setModel( d->m_routingModel ); d->m_routingLayer->synchronizeWith( d->m_ui.directionsListView->selectionModel() ); } d->adjustInputWidgets(); } if ( d->m_inputWidgets.size() < 2 ) { addInputWidget(); } } void RoutingWidget::updateRouteState( RoutingManager::State state ) { clearTour(); switch ( state ) { case RoutingManager::Downloading: d->m_ui.routeComboBox->setVisible( false ); d->m_ui.routeComboBox->clear(); d->m_progressTimer.start(); d->m_ui.resultLabel->setVisible( false ); break; case RoutingManager::Retrieved: { d->m_progressTimer.stop(); d->m_ui.searchButton->setIcon( QIcon() ); if ( d->m_routingManager->routingModel()->rowCount() == 0 ) { const QString results = tr( "No route found" ); d->m_ui.resultLabel->setText(QLatin1String("") + results + QLatin1String("")); d->m_ui.resultLabel->setVisible( true ); } } break; } d->m_saveRouteButton->setEnabled( d->m_routingManager->routingModel()->rowCount() > 0 ); } void RoutingWidget::requestMapPosition( RoutingInputWidget *widget, bool enabled ) { pointSelectionCanceled(); if ( enabled ) { d->m_inputRequest = widget; d->m_widget->installEventFilter( this ); d->m_widget->setFocus( Qt::OtherFocusReason ); } } void RoutingWidget::retrieveSelectedPoint( const GeoDataCoordinates &coordinates ) { if ( d->m_inputRequest && d->m_inputWidgets.contains( d->m_inputRequest ) ) { d->m_inputRequest->setTargetPosition( coordinates ); d->m_widget->update(); } d->m_inputRequest = 0; d->m_widget->removeEventFilter( this ); } void RoutingWidget::adjustSearchButton() { d->adjustSearchButton(); } void RoutingWidget::pointSelectionCanceled() { if ( d->m_inputRequest && d->m_inputWidgets.contains( d->m_inputRequest ) ) { d->m_inputRequest->abortMapInputRequest(); } d->m_inputRequest = 0; d->m_widget->removeEventFilter( this ); } void RoutingWidget::configureProfile() { int index = d->m_ui.routingProfileComboBox->currentIndex(); if ( index != -1 ) { RoutingProfileSettingsDialog dialog( d->m_widget->model()->pluginManager(), d->m_routingManager->profilesModel(), this ); dialog.editProfile( d->m_ui.routingProfileComboBox->currentIndex() ); d->m_routeRequest->setRoutingProfile( d->m_routingManager->profilesModel()->profiles().at( index ) ); } } void RoutingWidget::updateProgress() { if ( !d->m_progressAnimation.isEmpty() ) { d->m_currentFrame = ( d->m_currentFrame + 1 ) % d->m_progressAnimation.size(); QIcon frame = d->m_progressAnimation[d->m_currentFrame]; d->m_ui.searchButton->setIcon( frame ); } } void RoutingWidget::updateAlternativeRoutes() { if ( d->m_ui.routeComboBox->count() == 1) { // Parts of the route may lie outside the route trip points GeoDataLatLonBox const bbox = d->m_routingManager->routingModel()->route().bounds(); if ( d->m_zoomRouteAfterDownload ) { d->m_zoomRouteAfterDownload = false; d->m_widget->centerOn( bbox ); } } d->m_ui.routeComboBox->setVisible( d->m_ui.routeComboBox->count() > 0 ); if ( d->m_ui.routeComboBox->currentIndex() < 0 && d->m_ui.routeComboBox->count() > 0 ) { d->m_ui.routeComboBox->setCurrentIndex( 0 ); } QString const results = tr( "routes found: %1" ).arg( d->m_ui.routeComboBox->count() ); d->m_ui.resultLabel->setText( results ); d->m_ui.resultLabel->setVisible( true ); d->m_saveRouteButton->setEnabled( d->m_routingManager->routingModel()->rowCount() > 0 ); } void RoutingWidget::setShowDirectionsButtonVisible( bool visible ) { d->m_ui.showInstructionsButton->setVisible( visible ); } void RoutingWidget::setRouteSyncManager(RouteSyncManager *manager) { d->m_routeSyncManager = manager; connect( d->m_routeSyncManager, SIGNAL(routeSyncEnabledChanged(bool)), this, SLOT(updateCloudSyncButtons()) ); updateCloudSyncButtons(); } void RoutingWidget::openRoute() { QString const file = QFileDialog::getOpenFileName( this, tr( "Open Route" ), d->m_routingManager->lastOpenPath(), tr("KML Files (*.kml)") ); if ( !file.isEmpty() ) { d->m_routingManager->setLastOpenPath( QFileInfo( file ).absolutePath() ); d->m_zoomRouteAfterDownload = true; d->m_routingManager->loadRoute( file ); updateAlternativeRoutes(); } } void RoutingWidget::selectFirstProfile() { int count = d->m_routingManager->profilesModel()->rowCount(); if ( count && d->m_ui.routingProfileComboBox->currentIndex() < 0 ) { d->m_ui.routingProfileComboBox->setCurrentIndex( 0 ); } } void RoutingWidget::setRoutingProfile( int index ) { if ( index >= 0 && index < d->m_routingManager->profilesModel()->rowCount() ) { d->m_routeRequest->setRoutingProfile( d->m_routingManager->profilesModel()->profiles().at( index ) ); } } void RoutingWidget::showDirections() { d->m_ui.directionsListView->setVisible( true ); } void RoutingWidget::saveRoute() { QString fileName = QFileDialog::getSaveFileName( this, tr( "Save Route" ), // krazy:exclude=qclasses d->m_routingManager->lastSavePath(), tr( "KML files (*.kml)" ) ); if ( !fileName.isEmpty() ) { // maemo 5 file dialog does not append the file extension if ( !fileName.endsWith(QLatin1String( ".kml" ), Qt::CaseInsensitive) ) { fileName += QLatin1String(".kml"); } d->m_routingManager->setLastSavePath( QFileInfo( fileName ).absolutePath() ); d->m_routingManager->saveRoute( fileName ); } } void RoutingWidget::uploadToCloud() { Q_ASSERT( d->m_routeSyncManager ); if (!d->m_routeUploadDialog) { d->m_routeUploadDialog = new QProgressDialog( d->m_widget ); d->m_routeUploadDialog->setWindowTitle( tr( "Uploading route..." ) ); d->m_routeUploadDialog->setMinimum( 0 ); d->m_routeUploadDialog->setMaximum( 100 ); d->m_routeUploadDialog->setAutoClose( true ); d->m_routeUploadDialog->setAutoReset( true ); connect( d->m_routeSyncManager, SIGNAL(routeUploadProgress(qint64,qint64)), this, SLOT(updateUploadProgress(qint64,qint64)) ); } d->m_routeUploadDialog->show(); d->m_routeSyncManager->uploadRoute(); } void RoutingWidget::openCloudRoutesDialog() { Q_ASSERT( d->m_routeSyncManager ); d->m_routeSyncManager->prepareRouteList(); QPointer dialog = new CloudRoutesDialog( d->m_routeSyncManager->model(), d->m_widget ); connect( d->m_routeSyncManager, SIGNAL(routeListDownloadProgress(qint64,qint64)), dialog, SLOT(updateListDownloadProgressbar(qint64,qint64)) ); connect( dialog, SIGNAL(downloadButtonClicked(QString)), d->m_routeSyncManager, SLOT(downloadRoute(QString)) ); connect( dialog, SIGNAL(openButtonClicked(QString)), this, SLOT(openCloudRoute(QString)) ); connect( dialog, SIGNAL(deleteButtonClicked(QString)), d->m_routeSyncManager, SLOT(deleteRoute(QString)) ); connect( dialog, SIGNAL(removeFromCacheButtonClicked(QString)), d->m_routeSyncManager, SLOT(removeRouteFromCache(QString)) ); connect( dialog, SIGNAL(uploadToCloudButtonClicked(QString)), d->m_routeSyncManager, SLOT(uploadRoute(QString)) ); dialog->exec(); delete dialog; } void RoutingWidget::updateActiveRoutingProfile() { RoutingProfile const profile = d->m_routingManager->routeRequest()->routingProfile(); QList const profiles = d->m_routingManager->profilesModel()->profiles(); d->m_ui.routingProfileComboBox->setCurrentIndex( profiles.indexOf( profile ) ); } void RoutingWidget::updateCloudSyncButtons() { bool const show = d->m_routeSyncManager && d->m_routeSyncManager->isRouteSyncEnabled(); d->m_cloudSyncSeparator->setVisible( show ); d->m_uploadToCloudAction->setVisible( show ); d->m_openCloudRoutesAction->setVisible( show ); } void RoutingWidget::openCloudRoute(const QString &identifier) { Q_ASSERT( d->m_routeSyncManager ); d->m_routeSyncManager->openRoute( identifier ); d->m_widget->centerOn( d->m_routingManager->routingModel()->route().bounds() ); } void RoutingWidget::updateUploadProgress(qint64 sent, qint64 total) { Q_ASSERT( d->m_routeUploadDialog ); d->m_routeUploadDialog->setValue( 100.0 * sent / total ); } bool RoutingWidget::eventFilter( QObject *o, QEvent *event ) { if ( o != d->m_widget ) { return QWidget::eventFilter( o, event ); } Q_ASSERT( d->m_inputRequest != 0 ); Q_ASSERT( d->m_inputWidgets.contains( d->m_inputRequest ) ); if ( event->type() == QEvent::MouseButtonPress ) { QMouseEvent *e = static_cast( event ); return e->button() == Qt::LeftButton; } if ( event->type() == QEvent::MouseButtonRelease ) { QMouseEvent *e = static_cast( event ); qreal lon( 0.0 ), lat( 0.0 ); if ( e->button() == Qt::LeftButton && d->m_widget->geoCoordinates( e->pos().x(), e->pos().y(), lon, lat, GeoDataCoordinates::Radian ) ) { retrieveSelectedPoint( GeoDataCoordinates( lon, lat ) ); return true; } else { return QWidget::eventFilter( o, event ); } } if ( event->type() == QEvent::MouseMove ) { d->m_widget->setCursor( Qt::CrossCursor ); return true; } if ( event->type() == QEvent::KeyPress ) { QKeyEvent *e = static_cast( event ); if ( e->key() == Qt::Key_Escape ) { pointSelectionCanceled(); return true; } return QWidget::eventFilter( o, event ); } return QWidget::eventFilter( o, event ); } void RoutingWidget::resizeEvent(QResizeEvent *e) { QWidget::resizeEvent(e); } void RoutingWidget::toggleRoutePlay() { if( !d->m_playback ){ if( d->m_routingModel->rowCount() != 0 ){ initializeTour(); } } if (!d->m_playback) return; if( !d->m_playing ){ d->m_playing = true; d->m_playButton->setIcon(QIcon(QStringLiteral(":/marble/playback-pause.png"))); if( d->m_playback ){ d->m_playback->play(); } } else { d->m_playing = false; d->m_playButton->setIcon(QIcon(QStringLiteral(":/marble/playback-play.png"))); d->m_playback->pause(); } } void RoutingWidget::initializeTour() { d->m_tour = new GeoDataTour; if( d->m_document ){ d->m_widget->model()->treeModel()->removeDocument( d->m_document ); delete d->m_document; } d->m_document = new GeoDataDocument; d->m_document->setId(QStringLiteral("tourdoc")); d->m_document->append( d->m_tour ); d->m_tour->setPlaylist( new GeoDataPlaylist ); Route const route = d->m_widget->model()->routingManager()->routingModel()->route(); GeoDataLineString path = route.path(); if ( path.size() < 1 ){ return; } QList waypoints; double totalDistance = 0.0; for( int i=0; i const allWaypoints = waypoints; totalDistance = 0.0; GeoDataCoordinates last = path.at( 0 ); int j=0; // next waypoint qreal planetRadius = d->m_widget->model()->planet()->radius(); for( int i=1; i= allWaypoints[j].distance && j+1 1 && distance < step ){ continue; } last = coordinates; GeoDataLookAt* lookat = new GeoDataLookAt; // Choose a zoom distance of 400, 600 or 800 meters based on the distance to the closest waypoint double const range = waypointDistance < 400 ? 400 : ( waypointDistance < 2000 ? 600 : 800 ); coordinates.setAltitude( range ); lookat->setCoordinates( coordinates ); lookat->setRange( range ); GeoDataFlyTo* flyto = new GeoDataFlyTo; double const duration = 0.75; flyto->setDuration( duration ); flyto->setView( lookat ); flyto->setFlyToMode( GeoDataFlyTo::Smooth ); d->m_tour->playlist()->addPrimitive( flyto ); if( !waypoints.empty() && totalDistance > waypoints.first().distance-100 ){ WaypointInfo const waypoint = waypoints.first(); waypoints.pop_front(); GeoDataAnimatedUpdate *updateCreate = new GeoDataAnimatedUpdate; updateCreate->setUpdate( new GeoDataUpdate ); updateCreate->update()->setCreate( new GeoDataCreate ); GeoDataPlacemark *placemarkCreate = new GeoDataPlacemark; QString const waypointId = QString( "waypoint-%1" ).arg( i, 0, 10 ); placemarkCreate->setId( waypointId ); placemarkCreate->setTargetId( d->m_document->id() ); placemarkCreate->setCoordinate( waypoint.coordinates ); GeoDataStyle::Ptr style(new GeoDataStyle); style->iconStyle().setIconPath( waypoint.maneuver.directionPixmap() ); placemarkCreate->setStyle( style ); updateCreate->update()->create()->append( placemarkCreate ); d->m_tour->playlist()->addPrimitive( updateCreate ); GeoDataAnimatedUpdate *updateDelete = new GeoDataAnimatedUpdate; updateDelete->setDelayedStart( 2 ); updateDelete->setUpdate( new GeoDataUpdate ); updateDelete->update()->setDelete( new GeoDataDelete ); GeoDataPlacemark *placemarkDelete = new GeoDataPlacemark; placemarkDelete->setTargetId( waypointId ); updateDelete->update()->getDelete()->append( placemarkDelete ); d->m_tour->playlist()->addPrimitive( updateDelete ); } } d->m_playback = new TourPlayback; d->m_playback->setMarbleWidget( d->m_widget ); d->m_playback->setTour( d->m_tour ); d->m_widget->model()->treeModel()->addDocument( d->m_document ); QObject::connect( d->m_playback, SIGNAL(finished()), this, SLOT(seekTourToStart()) ); } void RoutingWidget::centerOn( const GeoDataCoordinates &coordinates ) { if ( d->m_widget ) { GeoDataLookAt lookat; lookat.setCoordinates( coordinates ); lookat.setRange( coordinates.altitude() ); d->m_widget->flyTo( lookat, Instant ); } } void RoutingWidget::clearTour() { d->m_playing = false; d->m_playButton->setIcon(QIcon(QStringLiteral(":/marble/playback-play.png"))); delete d->m_playback; d->m_playback = 0; if( d->m_document ){ d->m_widget->model()->treeModel()->removeDocument( d->m_document ); delete d->m_document; d->m_document = 0; d->m_tour = 0; } } void RoutingWidget::seekTourToStart() { Q_ASSERT( d->m_playback ); d->m_playback->stop(); d->m_playback->seek( 0 ); d->m_playButton->setIcon(QIcon(QStringLiteral(":/marble/playback-play.png"))); d->m_playing = false; } void RoutingWidget::handlePlanetChange() { const QString newPlanetId = d->m_widget->model()->planetId(); if (newPlanetId == d->m_planetId) { return; } d->m_planetId = newPlanetId; d->m_routingManager->clearRoute(); } } // namespace Marble #include "moc_RoutingWidget.cpp" diff --git a/src/plugins/render/annotate/AnnotatePlugin.cpp b/src/plugins/render/annotate/AnnotatePlugin.cpp index cbfc3fe65..6cd14f7a2 100644 --- a/src/plugins/render/annotate/AnnotatePlugin.cpp +++ b/src/plugins/render/annotate/AnnotatePlugin.cpp @@ -1,1771 +1,1769 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2009 Andrew Manson // Copyright 2013 Thibaut Gridel // Copyright 2014 Calin Cruceru // // Self #include "AnnotatePlugin.h" // Qt #include #include #include #include #include #include // Marble #include "MarbleDebug.h" #include "EditGroundOverlayDialog.h" #include "EditPlacemarkDialog.h" #include "EditPolygonDialog.h" #include "GeoDataDocument.h" #include "GeoDataGroundOverlay.h" #include "GeoDataLatLonBox.h" #include "GeoDataParser.h" #include "GeoDataPlacemark.h" #include "GeoDataStyle.h" #include "GeoDataLabelStyle.h" #include "GeoDataLineStyle.h" +#include "GeoDataPoint.h" #include "GeoDataPolyStyle.h" #include "GeoDataTreeModel.h" -#include "GeoDataTypes.h" #include "GeoPainter.h" #include "GeoDataLatLonAltBox.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" #include "GeoWriter.h" #include "KmlElementDictionary.h" #include "MarbleDirs.h" #include "MarbleModel.h" #include "MarblePlacemarkModel.h" #include "MarbleWidget.h" #include "AreaAnnotation.h" #include "PlacemarkTextAnnotation.h" #include "TextureLayer.h" #include "SceneGraphicsTypes.h" #include "MergingPolygonNodesAnimation.h" #include "MergingPolylineNodesAnimation.h" #include "MarbleWidgetPopupMenu.h" #include "PolylineAnnotation.h" #include "EditPolylineDialog.h" #include "ParsingRunnerManager.h" #include "ViewportParams.h" #include "osm/OsmPlacemarkData.h" namespace Marble { AnnotatePlugin::AnnotatePlugin( const MarbleModel *model ) : RenderPlugin( model ), m_isInitialized( false ), m_widgetInitialized( false ), m_marbleWidget( 0 ), m_overlayRmbMenu(nullptr), m_polygonRmbMenu(nullptr), m_nodeRmbMenu(nullptr), m_textAnnotationRmbMenu(nullptr), m_polylineRmbMenu(nullptr), m_annotationDocument(nullptr), m_movedItem( 0 ), m_focusItem( 0 ), m_polylinePlacemark( 0 ), m_polygonPlacemark( 0 ), m_clipboardItem( 0 ), m_drawingPolygon( false ), m_drawingPolyline( false ), m_addingPlacemark( false ), m_editingDialogIsShown( false ) { setEnabled( true ); setVisible( true ); connect( this, SIGNAL(visibilityChanged(bool,QString)), SLOT(enableModel(bool)) ); } AnnotatePlugin::~AnnotatePlugin() { qDeleteAll( m_graphicsItems ); if ( m_marbleWidget ) { m_marbleWidget->model()->treeModel()->removeDocument( m_annotationDocument ); } delete m_overlayRmbMenu; delete m_polygonRmbMenu; delete m_nodeRmbMenu; delete m_textAnnotationRmbMenu; delete m_polylineRmbMenu; delete m_annotationDocument; // delete m_networkAccessManager; delete m_clipboardItem; qDeleteAll(m_actions); disconnect( this, SIGNAL(mouseMoveGeoPosition(QString)), m_marbleWidget, SIGNAL(mouseMoveGeoPosition(QString)) ); } QStringList AnnotatePlugin::backendTypes() const { return QStringList(QStringLiteral("annotation")); } QString AnnotatePlugin::renderPolicy() const { return QStringLiteral("ALWAYS"); } QStringList AnnotatePlugin::renderPosition() const { return QStringList(QStringLiteral("ALWAYS_ON_TOP")); } QString AnnotatePlugin::name() const { return tr( "Annotation" ); } QString AnnotatePlugin::guiString() const { return tr( "&Annotation" ); } QString AnnotatePlugin::nameId() const { return QStringLiteral("annotation"); } QString AnnotatePlugin::description() const { return tr( "Draws annotations on maps with placemarks or polygons." ); } QString AnnotatePlugin::version() const { return QStringLiteral("1.0"); } QString AnnotatePlugin::copyrightYears() const { return QStringLiteral("2009, 2013"); } QVector AnnotatePlugin::pluginAuthors() const { return QVector() << PluginAuthor(QStringLiteral("Andrew Manson"), QStringLiteral("g.real.ate@gmail.com")) << PluginAuthor(QStringLiteral("Thibaut Gridel"), QStringLiteral("tgridel@free.fr")) << PluginAuthor(QStringLiteral("Calin Cruceru"), QStringLiteral("crucerucalincristian@gmail.com")); } QIcon AnnotatePlugin::icon() const { return QIcon(QStringLiteral(":/icons/draw-placemark.png")); } void AnnotatePlugin::initialize() { if ( !m_isInitialized ) { m_widgetInitialized = false; delete m_polygonPlacemark; m_polygonPlacemark = 0; delete m_movedItem; m_movedItem = 0; m_drawingPolygon = false; m_drawingPolyline = false; m_addingPlacemark = false; delete m_annotationDocument; m_annotationDocument = new GeoDataDocument; m_annotationDocument->setName( tr("Annotations") ); m_annotationDocument->setDocumentRole( UserDocument ); // Default polygon style GeoDataStyle::Ptr defaultPolygonStyle(new GeoDataStyle); GeoDataPolyStyle polyStyle; GeoDataLineStyle edgeStyle; GeoDataLabelStyle labelStyle; QColor polygonColor = QApplication::palette().highlight().color(); QColor edgeColor = QApplication::palette().light().color(); QColor labelColor = QApplication::palette().brightText().color(); polygonColor.setAlpha( 80 ); polyStyle.setColor( polygonColor ); edgeStyle.setColor( edgeColor ); labelStyle.setColor( labelColor ); defaultPolygonStyle->setId(QStringLiteral("polygon")); defaultPolygonStyle->setPolyStyle( polyStyle ); defaultPolygonStyle->setLineStyle( edgeStyle ); defaultPolygonStyle->setLabelStyle( labelStyle ); m_annotationDocument->addStyle( defaultPolygonStyle ); // Default polyline style GeoDataStyle::Ptr defaultPolylineStyle(new GeoDataStyle); GeoDataLineStyle lineStyle; QColor polylineColor = Qt::white; lineStyle.setColor( polylineColor ); lineStyle.setWidth( 1 ); defaultPolylineStyle->setId(QStringLiteral("polyline")); defaultPolylineStyle->setLineStyle( lineStyle ); defaultPolylineStyle->setLabelStyle( labelStyle ); m_annotationDocument->addStyle( defaultPolylineStyle ); m_isInitialized = true; } } bool AnnotatePlugin::isInitialized() const { return m_isInitialized; } QString AnnotatePlugin::runtimeTrace() const { return QStringLiteral("Annotate Items: %1").arg(m_annotationDocument->size()); } const QList *AnnotatePlugin::actionGroups() const { return &m_actions; } bool AnnotatePlugin::render(GeoPainter *painter, ViewportParams *viewport, const QString &renderPos, GeoSceneLayer *layer) { Q_UNUSED( renderPos ); Q_UNUSED( layer ); QListIterator iter( m_graphicsItems ); while ( iter.hasNext() ) { iter.next()->paint( painter, viewport, "Annotation", -1 ); } return true; } void AnnotatePlugin::enableModel( bool enabled ) { if ( enabled ) { if ( m_marbleWidget ) { setupActions( m_marbleWidget ); m_marbleWidget->model()->treeModel()->addDocument( m_annotationDocument ); } } else { setupActions( 0 ); if ( m_marbleWidget ) { m_marbleWidget->model()->treeModel()->removeDocument( m_annotationDocument ); } } } void AnnotatePlugin::setAddingPolygonHole( bool enabled ) { if ( enabled ) { announceStateChanged( SceneGraphicsItem::AddingPolygonHole ); } else { announceStateChanged( SceneGraphicsItem::Editing ); } } void AnnotatePlugin::setAddingNodes( bool enabled ) { if ( enabled ) { announceStateChanged( SceneGraphicsItem::AddingNodes ); } else { announceStateChanged( SceneGraphicsItem::Editing ); } } void AnnotatePlugin::setAreaAvailable() { static_cast( m_focusItem )->setBusy( false ); announceStateChanged( SceneGraphicsItem::Editing ); enableAllActions( m_actions.first() ); disableFocusActions(); enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicAreaAnnotation ); emit repaintNeeded(); } void AnnotatePlugin::setPolylineAvailable() { static_cast( m_focusItem )->setBusy( false ); announceStateChanged( SceneGraphicsItem::Editing ); enableAllActions( m_actions.first() ); disableFocusActions(); enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicPolylineAnnotation ); emit repaintNeeded(); } void AnnotatePlugin::askToRemoveFocusItem() { const int result = QMessageBox::question( m_marbleWidget, QObject::tr( "Remove current item" ), QObject::tr( "Are you sure you want to remove the current item?" ), QMessageBox::Yes | QMessageBox::No ); if ( result == QMessageBox::Yes ) { removeFocusItem(); } } void AnnotatePlugin::removeFocusItem() { // Ground Overlays will always be a special case.. if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) { for ( int i = 0; i < m_groundOverlayModel.rowCount(); ++i ) { const QModelIndex index = m_groundOverlayModel.index( i, 0 ); GeoDataGroundOverlay *overlay = dynamic_cast( qvariant_cast( index.data( MarblePlacemarkModel::ObjectPointerRole ) ) ); m_marbleWidget->model()->treeModel()->removeFeature( overlay ); } clearOverlayFrames(); } else { disableFocusActions(); m_graphicsItems.removeAll( m_focusItem ); m_marbleWidget->model()->treeModel()->removeFeature( m_focusItem->placemark() ); delete m_focusItem->placemark(); delete m_focusItem; m_movedItem = 0; m_focusItem = 0; } } void AnnotatePlugin::clearAnnotations() { const int result = QMessageBox::question( m_marbleWidget, QObject::tr( "Clear all annotations" ), QObject::tr( "Are you sure you want to clear all annotations?" ), QMessageBox::Yes | QMessageBox::Cancel ); if ( result == QMessageBox::Yes ) { disableFocusActions(); qDeleteAll( m_graphicsItems ); m_graphicsItems.clear(); m_marbleWidget->model()->treeModel()->removeDocument( m_annotationDocument ); m_annotationDocument->clear(); m_marbleWidget->model()->treeModel()->addDocument( m_annotationDocument ); m_movedItem = 0; m_focusItem = 0; } } void AnnotatePlugin::saveAnnotationFile() { const QString filename = QFileDialog::getSaveFileName( 0, tr("Save Annotation File"), QString(), tr("All Supported Files (*.kml *.osm);;" "KML file (*.kml);;" "Open Street Map file (*.osm)") ); if ( !filename.isNull() ) { GeoWriter writer; // FIXME: This should be consistent with the way the loading is done. if (filename.endsWith(QLatin1String(".kml"), Qt::CaseInsensitive)) { writer.setDocumentType( kml::kmlTag_nameSpaceOgc22 ); } else if (filename.endsWith(QLatin1String(".osm"), Qt::CaseInsensitive)) { // "0.6" is the current version of osm, it is used to identify the osm writer // The reference value is kept in plugins/runner/osm/OsmElementDictionary.hz writer.setDocumentType( "0.6" ); } QFile file( filename ); file.open( QIODevice::WriteOnly ); if ( !writer.write( &file, m_annotationDocument ) ) { mDebug() << "Could not write the file " << filename; } file.close(); } } void AnnotatePlugin::loadAnnotationFile() { const QString filename = QFileDialog::getOpenFileName( 0, tr("Open Annotation File"), QString(), tr("All Supported Files (*.kml *.osm);;" "Kml Annotation file (*.kml);;" "Open Street Map file (*.osm)") ); if ( filename.isNull() ) { return; } ParsingRunnerManager manager( m_marbleWidget->model()->pluginManager() ); GeoDataDocument *document = manager.openFile( filename ); Q_ASSERT( document ); // FIXME: The same problem as in the case of copying/cutting graphic items applies here: // the files do not load properly because the geometry copy is not a deep copy. for ( GeoDataFeature *feature: document->featureList() ) { - if ( feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) { - GeoDataPlacemark *placemark = static_cast( feature ); + if (const GeoDataPlacemark *placemark = geodata_cast(feature)) { GeoDataPlacemark *newPlacemark = new GeoDataPlacemark( *placemark ); - if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPointType ) { + if (geodata_cast(placemark->geometry())) { PlacemarkTextAnnotation *placemark = new PlacemarkTextAnnotation( newPlacemark ); m_graphicsItems.append( placemark ); - } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { + } else if (geodata_cast(placemark->geometry())) { newPlacemark->setParent( m_annotationDocument ); if ( !placemark->styleUrl().isEmpty() ) { newPlacemark->setStyleUrl( placemark->styleUrl() ); } AreaAnnotation *polygonAnnotation = new AreaAnnotation( newPlacemark ); m_graphicsItems.append( polygonAnnotation ); - } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { + } else if (geodata_cast(placemark->geometry())) { newPlacemark->setParent( m_annotationDocument ); if ( !placemark->styleUrl().isEmpty() ) { newPlacemark->setStyleUrl( placemark->styleUrl() ); } PolylineAnnotation *polylineAnnotation = new PolylineAnnotation( newPlacemark ); m_graphicsItems.append( polylineAnnotation ); } m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, newPlacemark ); - } else if ( feature->nodeType() == GeoDataTypes::GeoDataGroundOverlayType ) { - GeoDataGroundOverlay *overlay = static_cast( feature ); + } else if (const GeoDataGroundOverlay *overlay = geodata_cast(feature)) { GeoDataGroundOverlay *newOverlay = new GeoDataGroundOverlay( *overlay ); m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, newOverlay ); displayOverlayFrame( newOverlay ); } } m_marbleWidget->centerOn( document->latLonAltBox() ); delete document; emit repaintNeeded( QRegion() ); } bool AnnotatePlugin::eventFilter( QObject *watched, QEvent *event ) { if ( !m_widgetInitialized ) { MarbleWidget *marbleWidget = qobject_cast( watched ); if ( marbleWidget ) { m_marbleWidget = marbleWidget; addContextItems(); setupGroundOverlayModel(); setupOverlayRmbMenu(); setupPolygonRmbMenu(); setupPolylineRmbMenu(); setupNodeRmbMenu(); setupTextAnnotationRmbMenu(); setupActions( marbleWidget ); m_marbleWidget->model()->treeModel()->addDocument( m_annotationDocument ); m_widgetInitialized = true; connect( this, SIGNAL(mouseMoveGeoPosition(QString)), m_marbleWidget, SIGNAL(mouseMoveGeoPosition(QString)) ); return true; } return false; } // Accept mouse and key press events. if ( event->type() != QEvent::MouseButtonPress && event->type() != QEvent::MouseButtonRelease && event->type() != QEvent::MouseMove && event->type() != QEvent::KeyPress && event->type() != QEvent::KeyRelease ) { return false; } // Handle key press events. if ( event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease ) { QKeyEvent * const keyEvent = static_cast( event ); Q_ASSERT( keyEvent ); if ( m_focusItem && ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation || m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) ) { if ( keyEvent->type() == QEvent::KeyPress && keyEvent->key() == Qt::Key_Control ) { announceStateChanged( SceneGraphicsItem::MergingNodes ); } if ( keyEvent->type() == QEvent::KeyRelease && keyEvent->key() == Qt::Key_Control ) { if ( ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation && static_cast( m_focusItem )->isBusy() ) || ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation && static_cast( m_focusItem )->isBusy() ) ) { return true; } announceStateChanged( SceneGraphicsItem::Editing ); } } // If we have an item which has the focus and the Escape key is pressed, set item's focus // to false. if ( m_focusItem && keyEvent->type() == QEvent::KeyPress && keyEvent->key() == Qt::Key_Escape && !m_editingDialogIsShown ) { disableFocusActions(); m_focusItem->setFocus( false ); m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() ); m_focusItem = 0; return true; } // If we have an item which has the focus and the Delete key is pressed, delete the item if ( m_focusItem && keyEvent->type() == QEvent::KeyPress && keyEvent->key() == Qt::Key_Delete && !m_editingDialogIsShown ) { askToRemoveFocusItem(); return true; } return false; } // Handle mouse events. QMouseEvent * const mouseEvent = dynamic_cast( event ); Q_ASSERT( mouseEvent ); // Get the geocoordinates from mouse pos screen coordinates. qreal lon, lat; const bool isOnGlobe = m_marbleWidget->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); if ( !isOnGlobe ) { return false; } // Deal with adding polygons and polylines. if ( ( m_drawingPolygon && handleDrawingPolygon( mouseEvent ) ) || ( m_drawingPolyline && handleDrawingPolyline( mouseEvent ) ) ) { return true; } // It is important to deal with Ground Overlay mouse release event here because it uses the // texture layer in order to make the rendering more efficient. if ( mouseEvent->type() == QEvent::MouseButtonRelease && m_groundOverlayModel.rowCount() ) { handleReleaseOverlay( mouseEvent ); } // It is important to deal with the MouseMove event here because it changes the state of the // selected item irrespective of the longitude/latitude the cursor moved to (excepting when // it is outside the globe, which is treated above). if ( mouseEvent->type() == QEvent::MouseMove && m_movedItem && handleMovingSelectedItem( mouseEvent ) ) { setupCursor( m_movedItem ); return true; } // Pass the event to Graphic Items. for ( SceneGraphicsItem *item: m_graphicsItems ) { if ( !item->containsPoint( mouseEvent->pos() ) ) { continue; } // If an edit dialog is visible, do not permit right clicking on items. if ( m_editingDialogIsShown && mouseEvent->type() == QEvent::MouseButtonPress && mouseEvent->button() == Qt::RightButton) { return true; } if ( !item->hasFocus() && item->graphicType() != SceneGraphicsTypes::SceneGraphicGroundOverlay ) { if ( mouseEvent->type() == QEvent::MouseButtonPress && mouseEvent->button() == Qt::LeftButton ) { item->setFocus( true ); disableFocusActions(); enableActionsOnItemType( item->graphicType() ); if ( m_focusItem && m_focusItem != item ) { m_focusItem->setFocus( false ); if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) { clearOverlayFrames(); } } m_focusItem = item; m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() ); return true; } return false; } if ( item->sceneEvent( event ) ) { setupCursor( item ); if ( mouseEvent->type() == QEvent::MouseButtonPress ) { handleSuccessfulPressEvent( mouseEvent, item ); } else if ( mouseEvent->type() == QEvent::MouseMove ) { handleSuccessfulHoverEvent( mouseEvent, item ); } else if ( mouseEvent->type() == QEvent::MouseButtonRelease ) { handleSuccessfulReleaseEvent( mouseEvent, item ); } handleRequests( mouseEvent, item ); return true; } } // If the event gets here, it most probably means it is a map interaction event, or something // that has nothing to do with the annotate plugin items. We "deal" with this situation because, // for example, we may need to deselect some selected items. handleUncaughtEvents( mouseEvent ); return false; } bool AnnotatePlugin::handleDrawingPolygon( QMouseEvent *mouseEvent ) { const GeoDataCoordinates coords = mouseGeoDataCoordinates( mouseEvent ); if ( mouseEvent->type() == QEvent::MouseMove ) { setupCursor( 0 ); emit mouseMoveGeoPosition( coords.toString() ); return true; } else if ( mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QEvent::MouseButtonPress ) { m_marbleWidget->model()->treeModel()->removeFeature( m_polygonPlacemark ); GeoDataPolygon *poly = dynamic_cast( m_polygonPlacemark->geometry() ); poly->outerBoundary().append( coords ); m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polygonPlacemark ); emit nodeAdded( coords ); return true; } return false; } bool AnnotatePlugin::handleDrawingPolyline( QMouseEvent *mouseEvent ) { const GeoDataCoordinates coords = mouseGeoDataCoordinates( mouseEvent ); if ( mouseEvent->type() == QEvent::MouseMove ) { setupCursor( 0 ); emit mouseMoveGeoPosition( coords.toString() ); return true; } else if ( mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QEvent::MouseButtonPress ) { m_marbleWidget->model()->treeModel()->removeFeature( m_polylinePlacemark ); GeoDataLineString *line = dynamic_cast( m_polylinePlacemark->geometry() ); line->append( coords ); m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polylinePlacemark ); emit nodeAdded( coords ); return true; } return false; } void AnnotatePlugin::handleReleaseOverlay( QMouseEvent *mouseEvent ) { const GeoDataCoordinates coords = mouseGeoDataCoordinates( mouseEvent ); for ( int i = 0; i < m_groundOverlayModel.rowCount(); ++i ) { const QModelIndex index = m_groundOverlayModel.index( i, 0 ); GeoDataGroundOverlay *overlay = dynamic_cast( qvariant_cast( index.data( MarblePlacemarkModel::ObjectPointerRole ) ) ); if ( overlay->latLonBox().contains( coords ) ) { if ( mouseEvent->button() == Qt::LeftButton ) { displayOverlayFrame( overlay ); } else if ( mouseEvent->button() == Qt::RightButton ) { showOverlayRmbMenu( overlay, mouseEvent->x(), mouseEvent->y() ); } } } } bool AnnotatePlugin::handleMovingSelectedItem( QMouseEvent *mouseEvent ) { // Handling easily the mouse move by calling for each scene graphic item their own mouseMoveEvent // handler and updating their feature. if ( m_movedItem->sceneEvent( mouseEvent ) ) { m_marbleWidget->model()->treeModel()->updateFeature( m_movedItem->placemark() ); emit itemMoved( m_movedItem->placemark() ); if ( m_movedItem->graphicType() == SceneGraphicsTypes::SceneGraphicTextAnnotation ) { emit placemarkMoved(); } const GeoDataCoordinates coords = mouseGeoDataCoordinates( mouseEvent ); emit mouseMoveGeoPosition( coords.toString() ); return true; } return false; } void AnnotatePlugin::handleSuccessfulPressEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item ) { Q_UNUSED( mouseEvent ); // Update the item's placemark. m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() ); // Store a pointer to the item for possible following move events only if its state is // either 'Editing' or 'AddingNodes' and the mouse left button has been used. if ( ( item->state() == SceneGraphicsItem::Editing || item->state() == SceneGraphicsItem::AddingNodes ) && mouseEvent->button() == Qt::LeftButton ) { m_movedItem = item; } } void AnnotatePlugin::handleSuccessfulHoverEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item ) { Q_UNUSED( mouseEvent ); m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() ); } void AnnotatePlugin::handleSuccessfulReleaseEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item ) { Q_UNUSED( mouseEvent ); // The item gets 'deselected' (from moving) at mouse release. m_movedItem = 0; // Update the item's placemark. m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() ); } void AnnotatePlugin::handleRequests( QMouseEvent *mouseEvent, SceneGraphicsItem *item ) { if ( item->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) { AreaAnnotation * const area = static_cast( item ); if ( area->request() == SceneGraphicsItem::ShowPolygonRmbMenu ) { showPolygonRmbMenu( mouseEvent->pos().x(), mouseEvent->pos().y() ); } else if ( area->request() == SceneGraphicsItem::ShowNodeRmbMenu ) { showNodeRmbMenu( mouseEvent->pos().x(), mouseEvent->pos().y() ); } else if ( area->request() == SceneGraphicsItem::StartPolygonAnimation ) { QPointer animation = area->animation(); connect( animation, SIGNAL(nodesMoved()), this, SIGNAL(repaintNeeded()) ); connect( animation, SIGNAL(animationFinished()), this, SLOT(setAreaAvailable()) ); area->setBusy( true ); disableActions( m_actions.first() ); animation->startAnimation(); } else if ( area->request() == SceneGraphicsItem::OuterInnerMergingWarning ) { QMessageBox::warning( m_marbleWidget, tr( "Operation not permitted" ), tr( "Cannot merge a node from polygon's outer boundary " "with a node from one of its inner boundaries." ) ); } else if ( area->request() == SceneGraphicsItem::InnerInnerMergingWarning ) { QMessageBox::warning( m_marbleWidget, tr( "Operation not permitted" ), tr( "Cannot merge two nodes from two different inner " "boundaries." ) ); } else if ( area->request() == SceneGraphicsItem::InvalidShapeWarning ) { QMessageBox::warning( m_marbleWidget, tr( "Operation not permitted" ), tr( "Cannot merge the selected nodes. Most probably " "this would make the polygon's outer boundary not " "contain all its inner boundary nodes." ) ); } else if ( area->request() == SceneGraphicsItem::RemovePolygonRequest ) { removeFocusItem(); } else if ( area->request() == SceneGraphicsItem::ChangeCursorPolygonNodeHover ) { m_marbleWidget->setCursor( Qt::PointingHandCursor ); } else if ( area->request() == SceneGraphicsItem::ChangeCursorPolygonBodyHover ) { m_marbleWidget->setCursor( Qt::SizeAllCursor ); } } else if ( item->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) { PolylineAnnotation * const polyline = static_cast( item ); if ( polyline->request() == SceneGraphicsItem::ShowPolylineRmbMenu ) { showPolylineRmbMenu( mouseEvent->x(), mouseEvent->y() ); } else if ( polyline->request() == SceneGraphicsItem::ShowNodeRmbMenu ) { showNodeRmbMenu( mouseEvent->x(), mouseEvent->y() ); } else if ( polyline->request() == SceneGraphicsItem::StartPolylineAnimation ) { QPointer animation = polyline->animation(); connect( animation, SIGNAL(nodesMoved()), this, SIGNAL(repaintNeeded()) ); connect( animation, SIGNAL(animationFinished()), this, SLOT(setPolylineAvailable()) ); polyline->setBusy( true ); disableActions( m_actions.first() ); animation->startAnimation(); } else if ( polyline->request() == SceneGraphicsItem::RemovePolylineRequest ) { removeFocusItem(); } else if ( polyline->request() == SceneGraphicsItem::ChangeCursorPolylineNodeHover ) { m_marbleWidget->setCursor( Qt::PointingHandCursor ); } else if ( polyline->request() == SceneGraphicsItem::ChangeCursorPolylineLineHover ) { m_marbleWidget->setCursor( Qt::SizeAllCursor ); } } else if ( item->graphicType() == SceneGraphicsTypes::SceneGraphicTextAnnotation ) { PlacemarkTextAnnotation * const textAnnotation = static_cast( item ); if ( textAnnotation->request() == SceneGraphicsItem::ShowPlacemarkRmbMenu ) { showTextAnnotationRmbMenu( mouseEvent->x(), mouseEvent->y() ); } else if ( textAnnotation->request() == SceneGraphicsItem::ChangeCursorPlacemarkHover ) { m_marbleWidget->setCursor( Qt::SizeAllCursor ); } } else if ( item->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ){ GroundOverlayFrame * const groundOverlay = static_cast( item ); if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayVerticalHover ) { m_marbleWidget->setCursor( Qt::SizeVerCursor ); } else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayHorizontalHover ) { m_marbleWidget->setCursor( Qt::SizeHorCursor ); } else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayBDiagHover ) { m_marbleWidget->setCursor( Qt::SizeBDiagCursor ); } else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayFDiagHover ) { m_marbleWidget->setCursor( Qt::SizeFDiagCursor ); } else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayBodyHover ) { m_marbleWidget->setCursor( Qt::SizeAllCursor ); } else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayRotateHover ) { m_marbleWidget->setCursor( Qt::CrossCursor ); } } } void AnnotatePlugin::handleUncaughtEvents( QMouseEvent *mouseEvent ) { Q_UNUSED( mouseEvent ); // If the event is not caught by any of the annotate plugin specific items, clear the frames // (which have the meaning of deselecting the overlay). if ( !m_groundOverlayFrames.isEmpty() && mouseEvent->type() != QEvent::MouseMove && mouseEvent->type() != QEvent::MouseButtonRelease ) { clearOverlayFrames(); } if ( m_focusItem && m_focusItem->graphicType() != SceneGraphicsTypes::SceneGraphicGroundOverlay ) { if ( ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation && static_cast( m_focusItem )->isBusy() ) || ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation && static_cast( m_focusItem )->isBusy() ) ) { return; } m_focusItem->dealWithItemChange( 0 ); m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() ); if ( mouseEvent->type() == QEvent::MouseButtonPress ) { m_focusItem->setFocus( false ); disableFocusActions(); announceStateChanged( SceneGraphicsItem::Editing ); m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() ); m_focusItem = 0; } } } void AnnotatePlugin::setupActions( MarbleWidget *widget ) { qDeleteAll( m_actions ); m_actions.clear(); if ( !widget ) { return; } QActionGroup *group = new QActionGroup( 0 ); group->setExclusive( true ); QAction *selectItem = new QAction( QIcon(QStringLiteral(":/icons/edit-select.png")), tr("Select Item"), this ); selectItem->setCheckable( true ); selectItem->setChecked( true ); QAction *drawPolygon = new QAction( QIcon(QStringLiteral(":/icons/draw-polygon.png")), tr("Add Polygon"), this ); connect( drawPolygon, SIGNAL(triggered()), this, SLOT(addPolygon()) ); QAction *addHole = new QAction( QIcon(QStringLiteral(":/icons/polygon-draw-hole.png")), tr("Add Polygon Hole"), this ); addHole->setCheckable( true ); addHole->setEnabled( false ); connect( addHole, SIGNAL(toggled(bool)), this, SLOT(setAddingPolygonHole(bool)) ); QAction *addNodes = new QAction( QIcon(QStringLiteral(":/icons/polygon-add-nodes.png")), tr("Add Nodes"), this ); addNodes->setCheckable( true ); addNodes->setEnabled( false ); connect( addNodes, SIGNAL(toggled(bool)), this, SLOT(setAddingNodes(bool)) ); QAction *addTextAnnotation = new QAction( QIcon(QStringLiteral(":/icons/add-placemark.png")), tr("Add Placemark"), this ); connect( addTextAnnotation, SIGNAL(triggered()), this, SLOT(addTextAnnotation()) ); QAction *addPath = new QAction( QIcon(QStringLiteral(":/icons/draw-path.png")), tr("Add Path"), this ); connect( addPath, SIGNAL(triggered()), this, SLOT(addPolyline()) ); QAction *addOverlay = new QAction( QIcon(QStringLiteral(":/icons/draw-overlay.png")), tr("Add Ground Overlay"), this ); connect( addOverlay, SIGNAL(triggered()), this, SLOT(addOverlay()) ); QAction *removeItem = new QAction( QIcon(QStringLiteral(":/icons/edit-delete-shred.png")), tr("Remove Item"), this ); removeItem->setEnabled( false ); connect( removeItem, SIGNAL(triggered()), this, SLOT(askToRemoveFocusItem()) ); QAction *loadAnnotationFile = new QAction( QIcon(QStringLiteral(":/icons/open-for-editing.png")), tr("Load Annotation File" ), this ); connect( loadAnnotationFile, SIGNAL(triggered()), this, SLOT(loadAnnotationFile()) ); QAction *saveAnnotationFile = new QAction( QIcon(QStringLiteral(":/icons/document-save-as.png")), tr("Save Annotation File"), this ); connect( saveAnnotationFile, SIGNAL(triggered()), this, SLOT(saveAnnotationFile()) ); QAction *clearAnnotations = new QAction( QIcon(QStringLiteral(":/icons/remove.png")), tr("Clear all Annotations"), this ); connect( drawPolygon, SIGNAL(toggled(bool)), clearAnnotations, SLOT(setDisabled(bool)) ); connect( clearAnnotations, SIGNAL(triggered()), this, SLOT(clearAnnotations()) ); QAction *sep1 = new QAction( this ); sep1->setSeparator( true ); QAction *sep2 = new QAction( this ); sep2->setSeparator( true ); sep2->setObjectName( "toolbarSeparator" ); QAction *sep3 = new QAction( this ); sep3->setSeparator( true ); QAction *sep4 = new QAction( this ); sep4->setSeparator( true ); group->addAction( loadAnnotationFile ); group->addAction( saveAnnotationFile ); group->addAction( sep1 ); group->addAction( addTextAnnotation ); group->addAction( drawPolygon ); group->addAction( addPath ); group->addAction( addOverlay ); group->addAction( sep2 ); group->addAction( selectItem ); group->addAction( addHole ); group->addAction( addNodes ); group->addAction( removeItem ); group->addAction( sep3 ); group->addAction( clearAnnotations ); group->addAction( sep4 ); m_actions.append( group ); emit actionGroupsChanged(); } void AnnotatePlugin::disableActions( QActionGroup *group ) { for ( int i = 0; i < group->actions().size(); ++i ) { if ( group->actions().at(i)->text() != tr("Select Item") ) { group->actions().at(i)->setEnabled( false ); } else { group->actions().at(i)->setEnabled( true ); } } } void AnnotatePlugin::enableAllActions( QActionGroup *group ) { for ( int i = 0; i < group->actions().size(); ++i ) { group->actions().at(i)->setEnabled( true ); } } void AnnotatePlugin::enableActionsOnItemType( const QString &type ) { if ( type == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) { m_actions.first()->actions().at(9)->setEnabled( true ); m_actions.first()->actions().at(10)->setEnabled( true ); } else if ( type == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) { m_actions.first()->actions().at(10)->setEnabled( true ); } m_actions.first()->actions().at(11)->setEnabled( true ); } void AnnotatePlugin::disableFocusActions() { m_actions.first()->actions().at(8)->setChecked( true ); m_actions.first()->actions().at(9)->setEnabled( false ); m_actions.first()->actions().at(10)->setEnabled( false ); m_actions.first()->actions().at(11)->setEnabled( false ); } void AnnotatePlugin::addContextItems() { MarbleWidgetPopupMenu * const menu = m_marbleWidget->popupMenu(); m_pasteGraphicItem = new QAction( tr( "Paste" ), this ); m_pasteGraphicItem->setVisible( false ); connect( m_pasteGraphicItem, SIGNAL(triggered()), SLOT(pasteItem()) ); QAction *separator = new QAction( this ); separator->setSeparator( true ); bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; if ( !smallScreen ) { menu->addAction( Qt::RightButton, m_pasteGraphicItem ); menu->addAction( Qt::RightButton, separator ); } } void AnnotatePlugin::setupTextAnnotationRmbMenu() { delete m_textAnnotationRmbMenu; m_textAnnotationRmbMenu = new QMenu; QAction *cutItem = new QAction( tr( "Cut"), m_textAnnotationRmbMenu ); m_textAnnotationRmbMenu->addAction( cutItem ); connect( cutItem, SIGNAL(triggered()), this, SLOT(cutItem()) ); QAction *copyItem = new QAction( tr( "Copy"), m_textAnnotationRmbMenu ); m_textAnnotationRmbMenu->addAction( copyItem ); connect( copyItem, SIGNAL(triggered()), this, SLOT(copyItem()) ); QAction *removeItem = new QAction( tr( "Remove" ), m_textAnnotationRmbMenu ); m_textAnnotationRmbMenu->addAction( removeItem ); connect( removeItem, SIGNAL(triggered()), this, SLOT(askToRemoveFocusItem()) ); m_textAnnotationRmbMenu->addSeparator(); QAction *properties = new QAction( tr( "Properties" ), m_textAnnotationRmbMenu ); m_textAnnotationRmbMenu->addAction( properties ); connect( properties, SIGNAL(triggered()), this, SLOT(editTextAnnotation()) ); } void AnnotatePlugin::showTextAnnotationRmbMenu( qreal x, qreal y ) { m_textAnnotationRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) ); } void AnnotatePlugin::editTextAnnotation() { QPointer dialog = new EditPlacemarkDialog( m_focusItem->placemark(), &m_osmRelations, m_marbleWidget ); connect( dialog, SIGNAL(textAnnotationUpdated(GeoDataFeature*)), m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) ); connect( this, SIGNAL(placemarkMoved()), dialog, SLOT(updateDialogFields()) ); connect( dialog, SIGNAL(finished(int)), this, SLOT(stopEditingTextAnnotation(int)) ); connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ), this, SLOT( addRelation( const OsmPlacemarkData& ) ) ); dialog->setLabelColor(dynamic_cast(m_focusItem)->labelColor()); disableActions( m_actions.first() ); dialog->show(); m_editingDialogIsShown = true; m_editedItem = m_focusItem; } void AnnotatePlugin::addTextAnnotation() { m_addingPlacemark = true; // Get the normalized coordinates of the focus point. There will be automatically added a new // placemark. qreal lat = m_marbleWidget->focusPoint().latitude(); qreal lon = m_marbleWidget->focusPoint().longitude(); GeoDataCoordinates::normalizeLonLat( lon, lat ); GeoDataPlacemark *placemark = new GeoDataPlacemark; placemark->setCoordinate( lon, lat ); placemark->setVisible( true ); placemark->setBalloonVisible( false ); m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, placemark ); PlacemarkTextAnnotation *textAnnotation = new PlacemarkTextAnnotation( placemark ); textAnnotation->setFocus( true ); m_graphicsItems.append( textAnnotation ); QPointer dialog = new EditPlacemarkDialog( placemark, &m_osmRelations, m_marbleWidget ); connect( dialog, SIGNAL(textAnnotationUpdated(GeoDataFeature*)), m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) ); connect( this, SIGNAL(placemarkMoved()), dialog, SLOT(updateDialogFields()) ); connect( dialog, SIGNAL(finished(int)), this, SLOT(stopEditingTextAnnotation(int)) ); connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ), this, SLOT( addRelation( const OsmPlacemarkData& ) ) ); if ( m_focusItem ) { m_focusItem->setFocus( false ); if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) { clearOverlayFrames(); } } m_focusItem = textAnnotation; m_editedItem = textAnnotation; disableActions( m_actions.first() ); dialog->move( m_marbleWidget->mapToGlobal( QPoint( 0, 0 ) ) ); dialog->show(); m_editingDialogIsShown = true; } void AnnotatePlugin::stopEditingTextAnnotation( int result ) { m_focusItem = m_editedItem; m_editedItem = 0; announceStateChanged( SceneGraphicsItem::Editing ); enableAllActions( m_actions.first() ); disableFocusActions(); if ( !result && m_addingPlacemark ) { removeFocusItem(); } else { enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicTextAnnotation ); } m_addingPlacemark = false; m_editingDialogIsShown = false; } void AnnotatePlugin::setupGroundOverlayModel() { m_editingDialogIsShown = false; m_groundOverlayModel.setSourceModel( m_marbleWidget->model()->groundOverlayModel() ); m_groundOverlayModel.setDynamicSortFilter( true ); m_groundOverlayModel.setSortRole( MarblePlacemarkModel::PopularityIndexRole ); m_groundOverlayModel.sort( 0, Qt::AscendingOrder ); } void AnnotatePlugin::setupOverlayRmbMenu() { delete m_overlayRmbMenu; m_overlayRmbMenu = new QMenu; QAction *editOverlay = new QAction( tr( "Properties" ), m_overlayRmbMenu ); m_overlayRmbMenu->addAction( editOverlay ); connect( editOverlay, SIGNAL(triggered()), this, SLOT(editOverlay()) ); m_overlayRmbMenu->addSeparator(); QAction *removeOverlay = new QAction( tr( "Remove" ), m_overlayRmbMenu ); m_overlayRmbMenu->addAction( removeOverlay ); connect( removeOverlay, SIGNAL(triggered()), this, SLOT(removeOverlay()) ); } void AnnotatePlugin::addOverlay() { GeoDataGroundOverlay *overlay = new GeoDataGroundOverlay(); qreal centerLongitude = m_marbleWidget->viewport()->centerLongitude()*RAD2DEG; qreal centerLatitude = m_marbleWidget->viewport()->centerLatitude()*RAD2DEG; GeoDataLatLonAltBox box = m_marbleWidget->viewport()->viewLatLonAltBox(); qreal maxDelta = 20; qreal deltaLongitude = qMin(box.width(GeoDataCoordinates::Degree), maxDelta); qreal deltaLatitude = qMin(box.height(GeoDataCoordinates::Degree), maxDelta); qreal north = centerLatitude + deltaLatitude/4; qreal south = centerLatitude - deltaLatitude/4; qreal west = centerLongitude - deltaLongitude/4; qreal east = centerLongitude + deltaLongitude/4; overlay->latLonBox().setBoundaries( north, south, east, west, GeoDataCoordinates::Degree ); overlay->setName( tr( "Untitled Ground Overlay" ) ); QPointer dialog = new EditGroundOverlayDialog( overlay, m_marbleWidget->textureLayer(), m_marbleWidget ); dialog->exec(); if( dialog->result() ) { m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, overlay ); displayOverlayFrame( overlay ); } else { delete overlay; } delete dialog; } void AnnotatePlugin::showOverlayRmbMenu( GeoDataGroundOverlay *overlay, qreal x, qreal y ) { m_rmbOverlay = overlay; m_overlayRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) ); } void AnnotatePlugin::editOverlay() { displayOverlayFrame( m_rmbOverlay ); QPointer dialog = new EditGroundOverlayDialog( m_rmbOverlay, m_marbleWidget->textureLayer(), m_marbleWidget ); connect( dialog, SIGNAL(groundOverlayUpdated(GeoDataGroundOverlay*)), this, SLOT(updateOverlayFrame(GeoDataGroundOverlay*)) ); dialog->exec(); delete dialog; } void AnnotatePlugin::removeOverlay() { m_marbleWidget->model()->treeModel()->removeFeature( m_rmbOverlay ); clearOverlayFrames(); } void AnnotatePlugin::displayOverlayFrame( GeoDataGroundOverlay *overlay ) { if ( m_groundOverlayFrames.keys().contains( overlay ) ) { return; } GeoDataPolygon *polygon = new GeoDataPolygon( Tessellate ); polygon->outerBoundary().setTessellate( true ); GeoDataPlacemark *rectangle_placemark = new GeoDataPlacemark; rectangle_placemark->setGeometry( polygon ); rectangle_placemark->setParent( m_annotationDocument ); rectangle_placemark->setStyleUrl(QStringLiteral("#polygon")); m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, rectangle_placemark ); GroundOverlayFrame *frame = new GroundOverlayFrame( rectangle_placemark, overlay, m_marbleWidget->textureLayer() ); m_graphicsItems.append( frame ); m_groundOverlayFrames.insert( overlay, frame ); if ( m_focusItem ) { m_focusItem->setFocus( false ); } m_focusItem = frame; enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicGroundOverlay ); } void AnnotatePlugin::updateOverlayFrame( GeoDataGroundOverlay *overlay ) { GroundOverlayFrame *frame = static_cast( m_groundOverlayFrames.value( overlay ) ); if ( frame ) { frame->update(); } } void AnnotatePlugin::clearOverlayFrames() { for ( GeoDataGroundOverlay *overlay: m_groundOverlayFrames.keys() ) { GroundOverlayFrame *frame = static_cast( m_groundOverlayFrames.value( overlay ) ); m_graphicsItems.removeAll( m_groundOverlayFrames.value( overlay ) ); m_marbleWidget->model()->treeModel()->removeFeature( frame->placemark() ); delete frame->placemark(); delete frame; } m_groundOverlayFrames.clear(); m_focusItem = 0; disableFocusActions(); } void AnnotatePlugin::setupPolygonRmbMenu() { delete m_polygonRmbMenu; m_polygonRmbMenu = new QMenu; QAction *deselectNodes = new QAction( tr( "Deselect All Nodes" ), m_polygonRmbMenu ); m_polygonRmbMenu->addAction( deselectNodes ); connect( deselectNodes, SIGNAL(triggered()), this, SLOT(deselectNodes()) ); QAction *deleteAllSelected = new QAction( tr( "Delete All Selected Nodes" ), m_polygonRmbMenu ); m_polygonRmbMenu->addAction( deleteAllSelected ); connect( deleteAllSelected, SIGNAL(triggered()), this, SLOT(deleteSelectedNodes()) ); m_polygonRmbMenu->addSeparator(); QAction *cutPolygon = new QAction( tr( "Cut"), m_polygonRmbMenu ); m_polygonRmbMenu->addAction( cutPolygon ); connect( cutPolygon, SIGNAL(triggered()), this, SLOT(cutItem()) ); QAction *copyPolygon = new QAction( tr( "Copy"), m_polygonRmbMenu ); m_polygonRmbMenu->addAction( copyPolygon ); connect( copyPolygon, SIGNAL(triggered()), this, SLOT(copyItem()) ); QAction *removePolygon = new QAction( tr( "Remove" ), m_polygonRmbMenu ); m_polygonRmbMenu->addAction( removePolygon ); connect( removePolygon, SIGNAL(triggered()), this, SLOT(askToRemoveFocusItem()) ); m_polygonRmbMenu->addSeparator(); QAction *showEditDialog = new QAction( tr( "Properties" ), m_polygonRmbMenu ); m_polygonRmbMenu->addAction( showEditDialog ); connect( showEditDialog, SIGNAL(triggered()), this, SLOT(editPolygon()) ); } void AnnotatePlugin::showPolygonRmbMenu( qreal x, qreal y ) { // We need to store the coordinates from where the rmb menu is shown so that in case of // selecting Copy/Cut, we can move the polygon. qreal lon, lat; m_marbleWidget->geoCoordinates( x, y, lon, lat, GeoDataCoordinates::Radian ); m_fromWhereToCopy = GeoDataCoordinates( lon, lat ); if ( !static_cast( m_focusItem )->hasNodesSelected() ) { m_polygonRmbMenu->actions().at(1)->setEnabled( false ); m_polygonRmbMenu->actions().at(0)->setEnabled( false ); } else { m_polygonRmbMenu->actions().at(1)->setEnabled( true ); m_polygonRmbMenu->actions().at(0)->setEnabled( true ); } m_polygonRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) ); } void AnnotatePlugin::addPolygon() { m_drawingPolygon = true; GeoDataPolygon *poly = new GeoDataPolygon( Tessellate ); poly->outerBoundary().setTessellate( true ); m_polygonPlacemark = new GeoDataPlacemark; m_polygonPlacemark->setGeometry( poly ); m_polygonPlacemark->setParent( m_annotationDocument ); m_polygonPlacemark->setStyleUrl(QStringLiteral("#polygon")); m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polygonPlacemark ); AreaAnnotation *polygon = new AreaAnnotation( m_polygonPlacemark ); polygon->setState( SceneGraphicsItem::DrawingPolygon ); polygon->setFocus( true ); m_graphicsItems.append( polygon ); m_marbleWidget->update(); QPointer dialog = new EditPolygonDialog( m_polygonPlacemark, &m_osmRelations, m_marbleWidget ); connect( dialog, SIGNAL(polygonUpdated(GeoDataFeature*)), m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) ); connect( dialog, SIGNAL(finished(int)), this, SLOT(stopEditingPolygon(int)) ); connect( this, SIGNAL(nodeAdded(GeoDataCoordinates)), dialog, SLOT(handleAddingNode(GeoDataCoordinates)) ); connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ), this, SLOT( addRelation( const OsmPlacemarkData& ) ) ); // If there is another graphic item marked as 'selected' when pressing 'Add Polygon', change the focus of // that item. if ( m_focusItem ) { m_focusItem->setFocus( false ); if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) { clearOverlayFrames(); } } m_focusItem = polygon; m_editedItem = polygon; disableActions( m_actions.first() ); dialog->move( m_marbleWidget->mapToGlobal( QPoint( 0, 0 ) ) ); dialog->show(); m_editingDialogIsShown = true; } void AnnotatePlugin::stopEditingPolygon( int result ) { m_focusItem = m_editedItem; m_editedItem = 0; announceStateChanged( SceneGraphicsItem::Editing ); enableAllActions( m_actions.first() ); disableFocusActions(); if ( !result && m_drawingPolygon ) { removeFocusItem(); } else { enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicAreaAnnotation ); } m_editingDialogIsShown = false; m_drawingPolygon = false; m_polygonPlacemark = 0; } void AnnotatePlugin::deselectNodes() { if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) { AreaAnnotation * const area = static_cast( m_focusItem ); area->deselectAllNodes(); if ( area->request() == SceneGraphicsItem::NoRequest ) { m_marbleWidget->model()->treeModel()->updateFeature( area->placemark() ); } } else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) { PolylineAnnotation * const polyline = static_cast( m_focusItem ); polyline->deselectAllNodes(); if ( polyline->request() == SceneGraphicsItem::NoRequest ) { m_marbleWidget->model()->treeModel()->updateFeature( polyline->placemark() ); } } } void AnnotatePlugin::deleteSelectedNodes() { if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) { AreaAnnotation * const area = static_cast( m_focusItem ); area->deleteAllSelectedNodes(); } else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) { PolylineAnnotation * const polyline = static_cast( m_focusItem ); polyline->deleteAllSelectedNodes(); } if ( m_focusItem->request() == SceneGraphicsItem::NoRequest ) { m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() ); } else if ( m_focusItem->request() == SceneGraphicsItem::RemovePolygonRequest || m_focusItem->request() == SceneGraphicsItem::RemovePolylineRequest ) { removeFocusItem(); } else if ( m_focusItem->request() == SceneGraphicsItem::InvalidShapeWarning ) { QMessageBox::warning( m_marbleWidget, tr( "Operation not permitted" ), tr( "Cannot delete one of the selected nodes. Most probably " "this would make the polygon's outer boundary not " "contain all its inner boundary nodes." ) ); } } void AnnotatePlugin::editPolygon() { EditPolygonDialog *dialog = new EditPolygonDialog( m_focusItem->placemark(), &m_osmRelations, m_marbleWidget ); connect( dialog, SIGNAL(polygonUpdated(GeoDataFeature*)), m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) ); connect( dialog, SIGNAL(finished(int)), this, SLOT(stopEditingPolygon(int)) ); connect( this, SIGNAL(itemMoved(GeoDataPlacemark*)), dialog, SLOT(handleItemMoving(GeoDataPlacemark*)) ); connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ), this, SLOT( addRelation( const OsmPlacemarkData& ) ) ); disableActions( m_actions.first() ); dialog->move( m_marbleWidget->mapToGlobal( QPoint( 0, 0 ) ) ); dialog->show(); m_editingDialogIsShown = true; m_editedItem = m_focusItem; } void AnnotatePlugin::setupNodeRmbMenu() { delete m_nodeRmbMenu; m_nodeRmbMenu = new QMenu; QAction *selectNode = new QAction( tr( "Select Node" ), m_nodeRmbMenu ); m_nodeRmbMenu->addAction( selectNode ); connect( selectNode, SIGNAL(triggered()), this, SLOT(selectNode()) ); QAction *deleteNode = new QAction( tr( "Delete Node" ), m_nodeRmbMenu ); m_nodeRmbMenu->addAction( deleteNode ); connect( deleteNode, SIGNAL(triggered()), this, SLOT(deleteNode()) ); } void AnnotatePlugin::showNodeRmbMenu( qreal x, qreal y ) { // Check whether the node is already selected; we change the text of the action // accordingly. bool isSelected = false; if ( ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation && static_cast( m_focusItem )->clickedNodeIsSelected() ) || ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation && static_cast( m_focusItem )->clickedNodeIsSelected() ) ) { isSelected = true; } m_nodeRmbMenu->actions().first()->setText( isSelected ? tr("Deselect Node") : tr("Select Node") ); m_nodeRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) ); } void AnnotatePlugin::selectNode() { if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) { AreaAnnotation * const area = static_cast( m_focusItem ); area->changeClickedNodeSelection(); } else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) { PolylineAnnotation *const polyline = static_cast( m_focusItem ); polyline->changeClickedNodeSelection(); } if ( m_focusItem->request() == SceneGraphicsItem::NoRequest ) { m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() ); } } void AnnotatePlugin::deleteNode() { if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) { AreaAnnotation *area = static_cast( m_focusItem ); area->deleteClickedNode(); } else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) { PolylineAnnotation *polyline = static_cast( m_focusItem ); polyline->deleteClickedNode(); } if ( m_focusItem->request() == SceneGraphicsItem::NoRequest ) { m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() ); } else if ( m_focusItem->request() == SceneGraphicsItem::RemovePolygonRequest || m_focusItem->request() == SceneGraphicsItem::RemovePolylineRequest ) { removeFocusItem(); } else if ( m_focusItem->request() == SceneGraphicsItem::InvalidShapeWarning ) { QMessageBox::warning( m_marbleWidget, tr( "Operation not permitted" ), tr( "Cannot delete one of the selected nodes. Most probably " "this would make the polygon's outer boundary not " "contain all its inner boundary nodes." ) ); } } void AnnotatePlugin::setupPolylineRmbMenu() { delete m_polylineRmbMenu; m_polylineRmbMenu = new QMenu; QAction *deselectNodes = new QAction( tr( "Deselect All Nodes" ), m_polylineRmbMenu ); m_polylineRmbMenu->addAction( deselectNodes ); connect( deselectNodes, SIGNAL(triggered()), this, SLOT(deselectNodes()) ); QAction *deleteAllSelected = new QAction( tr( "Delete All Selected Nodes" ), m_polylineRmbMenu ); m_polylineRmbMenu->addAction( deleteAllSelected ); connect( deleteAllSelected, SIGNAL(triggered()), this, SLOT(deleteSelectedNodes()) ); m_polylineRmbMenu->addSeparator(); QAction *cutItem = new QAction( tr( "Cut"), m_polylineRmbMenu ); m_polylineRmbMenu->addAction( cutItem ); connect( cutItem, SIGNAL(triggered()), this, SLOT(cutItem()) ); QAction *copyItem = new QAction( tr( "Copy"), m_polylineRmbMenu ); m_polylineRmbMenu->addAction( copyItem ); connect( copyItem, SIGNAL(triggered()), this, SLOT(copyItem()) ); QAction *removeItem = new QAction( tr( "Remove" ), m_polylineRmbMenu ); m_polylineRmbMenu->addAction( removeItem ); connect( removeItem, SIGNAL(triggered()), this, SLOT(askToRemoveFocusItem()) ); m_polylineRmbMenu->addSeparator(); QAction *properties = new QAction( tr( "Properties" ), m_polylineRmbMenu ); m_polylineRmbMenu->addAction( properties ); connect( properties, SIGNAL(triggered()), this, SLOT(editPolyline()) ); } void AnnotatePlugin::showPolylineRmbMenu( qreal x, qreal y ) { qreal lon, lat; m_marbleWidget->geoCoordinates( x, y, lon, lat, GeoDataCoordinates::Radian ); m_fromWhereToCopy = GeoDataCoordinates( lon, lat ); if ( !static_cast( m_focusItem )->hasNodesSelected() ) { m_polylineRmbMenu->actions().at(1)->setEnabled( false ); m_polylineRmbMenu->actions().at(0)->setEnabled( false ); } else { m_polylineRmbMenu->actions().at(1)->setEnabled( true ); m_polylineRmbMenu->actions().at(0)->setEnabled( true ); } m_polylineRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) ); } void AnnotatePlugin::editPolyline() { QPointer dialog = new EditPolylineDialog( m_focusItem->placemark(), &m_osmRelations, m_marbleWidget ); connect( dialog, SIGNAL(polylineUpdated(GeoDataFeature*)), m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) ); connect( dialog, SIGNAL(finished(int)), this, SLOT(stopEditingPolyline(int)) ); connect( this, SIGNAL(itemMoved(GeoDataPlacemark*)), dialog, SLOT(handleItemMoving(GeoDataPlacemark*)) ); connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ), this, SLOT( addRelation( const OsmPlacemarkData& ) ) ); disableActions( m_actions.first() ); dialog->show(); m_editingDialogIsShown = true; m_editedItem = m_focusItem; } void AnnotatePlugin::addPolyline() { m_drawingPolyline = true; m_polylinePlacemark = new GeoDataPlacemark; m_polylinePlacemark->setGeometry( new GeoDataLineString( Tessellate ) ); m_polylinePlacemark->setParent( m_annotationDocument ); m_polylinePlacemark->setStyleUrl(QStringLiteral("#polyline")); m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polylinePlacemark ); PolylineAnnotation *polyline = new PolylineAnnotation( m_polylinePlacemark ); polyline->setState( SceneGraphicsItem::DrawingPolyline ); polyline->setFocus( true ); m_graphicsItems.append( polyline ); m_marbleWidget->update(); QPointer dialog = new EditPolylineDialog( m_polylinePlacemark, &m_osmRelations, m_marbleWidget ); connect( dialog, SIGNAL(polylineUpdated(GeoDataFeature*)), m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) ); connect( dialog, SIGNAL(finished(int)), this, SLOT(stopEditingPolyline(int)) ); connect( this, SIGNAL(nodeAdded(GeoDataCoordinates)), dialog, SLOT(handleAddingNode(GeoDataCoordinates)) ); connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ), this, SLOT( addRelation( const OsmPlacemarkData& ) ) ); if ( m_focusItem ) { m_focusItem->setFocus( false ); if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) { clearOverlayFrames(); } } m_focusItem = polyline; m_editedItem = m_focusItem; disableActions( m_actions.first() ); dialog->move( m_marbleWidget->mapToGlobal( QPoint( 0, 0 ) ) ); dialog->show(); m_editingDialogIsShown = true; } void AnnotatePlugin::stopEditingPolyline( int result ) { m_focusItem = m_editedItem; m_editedItem = 0; announceStateChanged( SceneGraphicsItem::Editing ); enableAllActions( m_actions.first() ); disableFocusActions(); if ( !result && m_drawingPolyline ) { removeFocusItem(); } else { enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicPolylineAnnotation ); } m_editingDialogIsShown = false; m_drawingPolyline = false; m_polylinePlacemark = 0; } void AnnotatePlugin::addRelation( const OsmPlacemarkData &relationData ) { m_osmRelations.insert( relationData.id(), relationData ); } void AnnotatePlugin::announceStateChanged( SceneGraphicsItem::ActionState newState ) { for ( SceneGraphicsItem *item: m_graphicsItems ) { item->setState( newState ); m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() ); } } void AnnotatePlugin::setupCursor( SceneGraphicsItem *item ) { if ( !item || item->state() == SceneGraphicsItem::AddingNodes ) { m_marbleWidget->setCursor( Qt::DragCopyCursor ); } else { // Nothing to do. The other cursor changes were moved to the handleRequests() section. } } void AnnotatePlugin::cutItem() { disableFocusActions(); // If there is already an item copied/cut, free its memory and replace it with this one. // The same applies when copying. if ( m_clipboardItem ) { delete m_clipboardItem->placemark(); delete m_clipboardItem; m_clipboardItem = 0; } m_clipboardItem = m_focusItem; m_pasteGraphicItem->setVisible( true ); m_graphicsItems.removeAll( m_focusItem ); m_marbleWidget->model()->treeModel()->removeFeature( m_focusItem->placemark() ); m_focusItem = 0; } void AnnotatePlugin::copyItem() { if ( m_clipboardItem ) { delete m_clipboardItem->placemark(); delete m_clipboardItem; m_clipboardItem = 0; } // Just copy the placemark and instantiate a new object based on its graphic type. // FIXME: Here is obvious a problem in the case of AreaAnnotation (when copying a // placemark which has a GeoDataPolygon geometry?). Later Edit: The same applies for // polylines (GeoDataLineString geometries). GeoDataPlacemark *placemark = new GeoDataPlacemark( *m_focusItem->placemark() ); if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) { m_clipboardItem = new AreaAnnotation( placemark ); } else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicTextAnnotation ) { m_clipboardItem = new PlacemarkTextAnnotation( placemark ); } else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) { m_clipboardItem = new PolylineAnnotation( placemark ); } m_pasteGraphicItem->setVisible( true ); } void AnnotatePlugin::pasteItem() { const QPoint eventPoint = m_marbleWidget->popupMenu()->mousePosition(); qreal lon, lat; m_marbleWidget->geoCoordinates( eventPoint.x(), eventPoint.y(), lon, lat, GeoDataCoordinates::Radian ); const GeoDataCoordinates newCoords( lon, lat ); m_clipboardItem->move( m_fromWhereToCopy, newCoords ); m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_clipboardItem->placemark() ); m_graphicsItems.append( m_clipboardItem ); m_clipboardItem->setFocus( true ); enableActionsOnItemType( m_clipboardItem->graphicType() ); m_focusItem = m_clipboardItem; m_clipboardItem = 0; m_pasteGraphicItem->setVisible( false ); } const GeoDataCoordinates AnnotatePlugin::mouseGeoDataCoordinates( QMouseEvent *mouseEvent ) { qreal lon, lat; m_marbleWidget->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); return GeoDataCoordinates( lon, lat ); } } #include "moc_AnnotatePlugin.cpp" diff --git a/src/plugins/render/annotate/AreaAnnotation.cpp b/src/plugins/render/annotate/AreaAnnotation.cpp index 78d44cba0..cbab71195 100644 --- a/src/plugins/render/annotate/AreaAnnotation.cpp +++ b/src/plugins/render/annotate/AreaAnnotation.cpp @@ -1,1527 +1,1526 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2009 Andrew Manson // Copyright 2013 Thibaut Gridel // Copyright 2014 Calin Cruceru // // Self #include "AreaAnnotation.h" // Qt #include #include #include #include // Marble #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" #include "GeoPainter.h" #include "ViewportParams.h" #include "SceneGraphicsTypes.h" #include "MarbleMath.h" #include "MergingPolygonNodesAnimation.h" #include "PolylineNode.h" #include "osm/OsmPlacemarkData.h" namespace Marble { const int AreaAnnotation::regularDim = 15; const int AreaAnnotation::selectedDim = 15; const int AreaAnnotation::mergedDim = 20; const int AreaAnnotation::hoveredDim = 20; const QColor AreaAnnotation::regularColor = Oxygen::aluminumGray3; const QColor AreaAnnotation::mergedColor = Oxygen::emeraldGreen6; AreaAnnotation::AreaAnnotation( GeoDataPlacemark *placemark ) : SceneGraphicsItem( placemark ), m_viewport( 0 ), m_regionsInitialized( false ), m_busy( false ), m_hoveredNode( -1, -1 ), m_interactingObj( InteractingNothing ), m_virtualHovered( -1, -1 ) { setPaintLayers(QStringList() << "AreaAnnotation"); } AreaAnnotation::~AreaAnnotation() { delete m_animation; } void AreaAnnotation::paint(GeoPainter *painter, const ViewportParams *viewport , const QString &layer, int tileZoomLevel) { Q_UNUSED(layer); Q_UNUSED(tileZoomLevel); m_viewport = viewport; - Q_ASSERT( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ); + Q_ASSERT(geodata_cast(placemark()->geometry())); painter->save(); if ( state() == SceneGraphicsItem::DrawingPolygon || !m_regionsInitialized ) { setupRegionsLists( painter ); m_regionsInitialized = true; } else { updateRegions( painter ); } if ( hasFocus() ) { drawNodes( painter ); } painter->restore(); } bool AreaAnnotation::containsPoint( const QPoint &point ) const { if ( m_busy ) { return false; } if ( state() == SceneGraphicsItem::Editing ) { return ( polygonContains( point ) && innerBoundsContain( point ) == -1 ) || outerNodeContains( point ) != -1 || innerNodeContains( point ) != QPair( -1, -1 ); } else if ( state() == SceneGraphicsItem::AddingPolygonHole ) { return polygonContains( point ) && outerNodeContains( point ) == -1 && innerNodeContains( point ) == QPair( -1, -1 ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { return outerNodeContains( point ) != -1 || innerNodeContains( point ) != QPair( -1, -1 ); } else if ( state() == SceneGraphicsItem::AddingNodes ) { return ( polygonContains( point ) && innerBoundsContain( point ) == -1 ) || virtualNodeContains( point ) != QPair( -1, -1 ) || innerNodeContains( point ) != QPair( -1, -1 ) || outerNodeContains( point ) != -1; } return false; } void AreaAnnotation::dealWithItemChange( const SceneGraphicsItem *other ) { Q_UNUSED( other ); // So far we only deal with item changes when hovering nodes, so that // they do not remain hovered when changing the item we interact with. if ( state() == SceneGraphicsItem::Editing ) { if ( m_hoveredNode != QPair( -1, -1 ) ) { const int i = m_hoveredNode.first; const int j = m_hoveredNode.second; if ( j == -1 ) { m_outerNodesList[i].setFlag( PolylineNode::NodeIsEditingHighlighted, false ); } else { m_innerNodesList[i][j].setFlag( PolylineNode::NodeIsEditingHighlighted, false ); } } m_hoveredNode = QPair( -1, -1 ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { if ( m_hoveredNode != QPair( -1, -1 ) ) { const int i = m_hoveredNode.first; const int j = m_hoveredNode.second; if ( j == -1 ) { m_outerNodesList[i].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } else { m_innerNodesList[i][j].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } } m_hoveredNode = QPair( -1, -1 ); } else if ( state() == SceneGraphicsItem::AddingNodes ) { m_virtualHovered = QPair( -1, -1 ); } } void AreaAnnotation::move( const GeoDataCoordinates &source, const GeoDataCoordinates &destination ) { GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); GeoDataLinearRing outerRing = polygon->outerBoundary(); QVector innerRings = polygon->innerBoundaries(); OsmPlacemarkData *osmData = 0; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); } polygon->outerBoundary().clear(); polygon->innerBoundaries().clear(); const qreal deltaLat = destination.latitude() - source.latitude(); const qreal deltaLon = destination.longitude() - source.longitude(); Quaternion latRectAxis = Quaternion::fromEuler( 0, destination.longitude(), 0); Quaternion latAxis = Quaternion::fromEuler( -deltaLat, 0, 0); Quaternion lonAxis = Quaternion::fromEuler(0, deltaLon, 0); Quaternion rotAxis = latRectAxis * latAxis * latRectAxis.inverse() * lonAxis; qreal lonRotated, latRotated; for ( int i = 0; i < outerRing.size(); ++i ) { Quaternion qpos = outerRing.at(i).quaternion(); qpos.rotateAroundAxis(rotAxis); qpos.getSpherical( lonRotated, latRotated ); GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 ); // Keeping the OsmPlacemarkData synchronized with the geometry if ( osmData ) { osmData->memberReference( -1 ).changeNodeReference( outerRing.at( i ), movedPoint ); } polygon->outerBoundary().append( movedPoint ); } for ( int i = 0; i < innerRings.size(); ++i ) { GeoDataLinearRing newRing( Tessellate ); for ( int j = 0; j < innerRings.at(i).size(); ++j ) { Quaternion qpos = innerRings.at(i).at(j).quaternion(); qpos.rotateAroundAxis(rotAxis); qpos.getSpherical( lonRotated, latRotated ); GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 ); if ( osmData ) { osmData->memberReference( i ).changeNodeReference( innerRings.at( i ).at( j ), movedPoint ); } newRing.append( movedPoint ); } polygon->innerBoundaries().append( newRing ); } } void AreaAnnotation::setBusy( bool enabled ) { m_busy = enabled; if ( !enabled && m_animation && state() == SceneGraphicsItem::MergingNodes ) { // Update the PolylineNodes lists after the animation has finished its execution. const int ff = m_firstMergedNode.first; const int fs = m_firstMergedNode.second; const int sf = m_secondMergedNode.first; const int ss = m_secondMergedNode.second; if ( ff != -1 && fs == -1 && sf != -1 && ss == -1 ) { m_outerNodesList[sf].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); m_hoveredNode = QPair( -1, -1 ); // Remove the merging node flag and add the NodeIsSelected flag if either one of the // merged nodes had been selected before merging them. m_outerNodesList[sf].setFlag( PolylineNode::NodeIsMerged, false ); if ( m_outerNodesList.at(ff).isSelected() ) { m_outerNodesList[sf].setFlag( PolylineNode::NodeIsSelected ); } m_outerNodesList.removeAt( ff ); m_firstMergedNode = QPair( -1, -1 ); m_secondMergedNode = QPair( -1, -1 ); } else if ( ff != -1 && fs != -1 && sf != -1 && ss != -1 ) { m_innerNodesList[sf][ss].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); m_hoveredNode = QPair( -1, -1 ); m_innerNodesList[sf][ss].setFlag( PolylineNode::NodeIsMerged, false ); if ( m_innerNodesList.at(ff).at(fs).isSelected() ) { m_innerNodesList[sf][ss].setFlag( PolylineNode::NodeIsSelected ); } m_innerNodesList[sf].removeAt( fs ); m_firstMergedNode = QPair( -1, -1 ); m_secondMergedNode = QPair( -1, -1 ); } delete m_animation; } } bool AreaAnnotation::isBusy() const { return m_busy; } void AreaAnnotation::deselectAllNodes() { if ( state() != SceneGraphicsItem::Editing ) { return; } for ( int i = 0 ; i < m_outerNodesList.size(); ++i ) { m_outerNodesList[i].setFlag( PolylineNode::NodeIsSelected, false ); } for ( int i = 0; i < m_innerNodesList.size(); ++i ) { for ( int j = 0; j < m_innerNodesList.at(i).size(); ++j ) { m_innerNodesList[i][j].setFlag( PolylineNode::NodeIsSelected, false ); } } } void AreaAnnotation::deleteAllSelectedNodes() { if ( state() != SceneGraphicsItem::Editing ) { return; } GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); GeoDataLinearRing &outerRing = polygon->outerBoundary(); QVector &innerRings = polygon->innerBoundaries(); OsmPlacemarkData *osmData = 0; OsmPlacemarkData initialOsmData; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); initialOsmData = placemark()->osmData(); } // If it proves inefficient, try something different. GeoDataLinearRing initialOuterRing = polygon->outerBoundary(); QVector initialInnerRings = polygon->innerBoundaries(); const QVector initialOuterNodes = m_outerNodesList; const QVector< QVector > initialInnerNodes = m_innerNodesList; for ( int i = 0; i < outerRing.size(); ++i ) { if ( m_outerNodesList.at(i).isSelected() ) { if ( m_outerNodesList.size() <= 3 ) { setRequest( SceneGraphicsItem::RemovePolygonRequest ); return; } if ( osmData ) { osmData->memberReference( -1 ).removeNodeReference( initialOuterRing.at( i ) ); } m_outerNodesList.removeAt( i ); outerRing.remove( i ); --i; } } for ( int i = 0; i < innerRings.size(); ++i ) { for ( int j = 0; j < innerRings.at(i).size(); ++j ) { if ( m_innerNodesList.at(i).at(j).isSelected() ) { if ( m_innerNodesList.at(i).size() <= 3 ) { if ( osmData ) { osmData->removeMemberReference( i ); } innerRings.remove( i ); m_innerNodesList.removeAt( i ); --i; break; } if ( osmData ) { osmData->memberReference( i ).removeNodeReference( initialInnerRings.at( i ).at( j ) ); } innerRings[i].remove( j ); m_innerNodesList[i].removeAt( j ); --j; } } } if ( !isValidPolygon() ) { if ( osmData ) { placemark()->setOsmData( initialOsmData ); } polygon->outerBoundary() = initialOuterRing; polygon->innerBoundaries() = initialInnerRings; m_outerNodesList = initialOuterNodes; m_innerNodesList = initialInnerNodes; setRequest( SceneGraphicsItem::InvalidShapeWarning ); } } void AreaAnnotation::deleteClickedNode() { if ( state() != SceneGraphicsItem::Editing ) { return; } GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); GeoDataLinearRing &outerRing = polygon->outerBoundary(); QVector &innerRings = polygon->innerBoundaries(); OsmPlacemarkData *osmData = 0; OsmPlacemarkData initialOsmData; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); initialOsmData = placemark()->osmData(); } // If it proves inefficient, try something different. GeoDataLinearRing initialOuterRing = polygon->outerBoundary(); QVector initialInnerRings = polygon->innerBoundaries(); const QVector initialOuterNodes = m_outerNodesList; const QVector< QVector > initialInnerNodes = m_innerNodesList; int i = m_clickedNodeIndexes.first; int j = m_clickedNodeIndexes.second; m_hoveredNode = QPair( -1, -1 ); if ( i != -1 && j == -1 ) { if ( m_outerNodesList.size() <= 3 ) { setRequest( SceneGraphicsItem::RemovePolygonRequest ); return; } // Keep the OsmPlacemarkData synchronized with the geometrys if ( osmData ) { osmData->removeNodeReference( outerRing.at( i ) ); } outerRing.remove( i ); m_outerNodesList.removeAt( i ); } else if ( i != -1 && j != -1 ) { if ( m_innerNodesList.at(i).size() <= 3 ) { if ( osmData ) { osmData->removeMemberReference( i ); } innerRings.remove( i ); m_innerNodesList.removeAt( i ); return; } if ( osmData ) { osmData->memberReference( i ).removeNodeReference( innerRings.at( i ).at( j ) ); } innerRings[i].remove( j ); m_innerNodesList[i].removeAt( j ); } if ( !isValidPolygon() ) { if ( osmData ) { placemark()->setOsmData( initialOsmData ); } polygon->outerBoundary() = initialOuterRing; polygon->innerBoundaries() = initialInnerRings; m_outerNodesList = initialOuterNodes; m_innerNodesList = initialInnerNodes; setRequest( SceneGraphicsItem::InvalidShapeWarning ); } } void AreaAnnotation::changeClickedNodeSelection() { if ( state() != SceneGraphicsItem::Editing ) { return; } const int i = m_clickedNodeIndexes.first; const int j = m_clickedNodeIndexes.second; if ( i != -1 && j == -1 ) { m_outerNodesList[i].setFlag( PolylineNode::NodeIsSelected, !m_outerNodesList.at(i).isSelected() ); } else if ( i != -1 && j != -1 ) { m_innerNodesList[i][j].setFlag( PolylineNode::NodeIsSelected, !m_innerNodesList.at(i).at(j).isSelected() ); } } bool AreaAnnotation::hasNodesSelected() const { for ( int i = 0; i < m_outerNodesList.size(); ++i ) { if ( m_outerNodesList.at(i).isSelected() ) { return true; } } for ( int i = 0; i < m_innerNodesList.size(); ++i ) { for ( int j = 0; j < m_innerNodesList.at(i).size(); ++j ) { if ( m_innerNodesList.at(i).at(j).isSelected() ) { return true; } } } return false; } bool AreaAnnotation::clickedNodeIsSelected() const { const int i = m_clickedNodeIndexes.first; const int j = m_clickedNodeIndexes.second; return ( i != -1 && j == -1 && m_outerNodesList.at(i).isSelected() ) || ( i != -1 && j != -1 && m_innerNodesList.at(i).at(j).isSelected() ); } QPointer AreaAnnotation::animation() { return m_animation; } bool AreaAnnotation::mousePressEvent( QMouseEvent *event ) { if ( !m_viewport || m_busy ) { return false; } setRequest( SceneGraphicsItem::NoRequest ); if ( state() == SceneGraphicsItem::Editing ) { return processEditingOnPress( event ); } else if ( state() == SceneGraphicsItem::AddingPolygonHole ) { return processAddingHoleOnPress( event ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { return processMergingOnPress( event ); } else if ( state() == SceneGraphicsItem::AddingNodes ) { return processAddingNodesOnPress( event ); } return false; } bool AreaAnnotation::mouseMoveEvent( QMouseEvent *event ) { if ( !m_viewport || m_busy ) { return false; } setRequest( SceneGraphicsItem::NoRequest ); if ( state() == SceneGraphicsItem::Editing ) { return processEditingOnMove( event ); } else if ( state() == SceneGraphicsItem::AddingPolygonHole ) { return processAddingHoleOnMove( event ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { return processMergingOnMove( event ); } else if ( state() == SceneGraphicsItem::AddingNodes ) { return processAddingNodesOnMove( event ); } return false; } bool AreaAnnotation::mouseReleaseEvent( QMouseEvent *event ) { if ( !m_viewport || m_busy ) { return false; } setRequest( SceneGraphicsItem::NoRequest ); if ( state() == SceneGraphicsItem::Editing ) { return processEditingOnRelease( event ); } else if ( state() == SceneGraphicsItem::AddingPolygonHole ) { return processAddingHoleOnRelease( event ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { return processMergingOnRelease( event ); } else if ( state() == SceneGraphicsItem::AddingNodes ) { return processAddingNodesOnRelease( event ); } return false; } void AreaAnnotation::dealWithStateChange( SceneGraphicsItem::ActionState previousState ) { // Dealing with cases when exiting a state has an effect on this item. if ( previousState == SceneGraphicsItem::Editing ) { // Make sure that when changing the state, there is no highlighted node. if ( m_hoveredNode != QPair( -1, -1 ) ) { const int i = m_hoveredNode.first; const int j = m_hoveredNode.second; if ( j == -1 ) { m_outerNodesList[i].setFlag( PolylineNode::NodeIsEditingHighlighted, false ); } else { m_innerNodesList[i][j].setFlag( PolylineNode::NodeIsEditingHighlighted, false ); } } m_clickedNodeIndexes = QPair( -1, -1 ); m_hoveredNode = QPair( -1, -1 ); } else if ( previousState == SceneGraphicsItem::AddingPolygonHole ) { // Check if a polygon hole was being drawn before changing state. GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); QVector &innerBounds = polygon->innerBoundaries(); if ( innerBounds.size() && innerBounds.last().size() <= 2 ) { // If only two nodes were added, remove this inner boundary entirely. innerBounds.remove( innerBounds.size() - 1 ); m_innerNodesList.removeLast(); return; } } else if ( previousState == SceneGraphicsItem::MergingNodes ) { // If there was only a node selected for being merged and the state changed, // deselect it. const int i = m_firstMergedNode.first; const int j = m_firstMergedNode.second; if ( i != -1 && j != -1 ) { m_innerNodesList[i][j].setFlag( PolylineNode::NodeIsMerged, false ); } else if ( i != -1 && j == -1 ) { m_outerNodesList[i].setFlag( PolylineNode::NodeIsMerged, false ); } // Make sure that when changing the state, there is no highlighted node. if ( m_hoveredNode != QPair( -1, -1 ) ) { int i = m_hoveredNode.first; int j = m_hoveredNode.second; if ( j == -1 ) { m_outerNodesList[i].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } else { m_innerNodesList[i][j].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } } m_firstMergedNode = QPair( -1, -1 ); m_hoveredNode = QPair( -1, -1 ); delete m_animation; } else if ( previousState == SceneGraphicsItem::AddingNodes ) { m_outerVirtualNodes.clear(); m_innerVirtualNodes.clear(); m_virtualHovered = QPair( -1, -1 ); m_adjustedNode = -2; } // Dealing with cases when entering a state has an effect on this item, or // initializations are needed. if ( state() == SceneGraphicsItem::Editing ) { m_interactingObj = InteractingNothing; m_clickedNodeIndexes = QPair( -1, -1 ); m_hoveredNode = QPair( -1, -1 ); } else if ( state() == SceneGraphicsItem::AddingPolygonHole ) { // Nothing to do so far when entering this state. GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); QVector &innerBounds = polygon->innerBoundaries(); m_innerNodesList.append(QVector()); innerBounds.append( GeoDataLinearRing( Tessellate ) ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { m_firstMergedNode = QPair( -1, -1 ); m_secondMergedNode = QPair( -1, -1 ); m_hoveredNode = QPair( -1, -1 ); m_animation = 0; } else if ( state() == SceneGraphicsItem::AddingNodes ) { m_virtualHovered = QPair( -1, -1 ); m_adjustedNode = -2; } } const char *AreaAnnotation::graphicType() const { return SceneGraphicsTypes::SceneGraphicAreaAnnotation; } bool AreaAnnotation::isValidPolygon() const { const GeoDataPolygon *poly = static_cast( placemark()->geometry() ); const QVector &innerRings = poly->innerBoundaries(); for ( const GeoDataLinearRing &innerRing: innerRings ) { for ( int i = 0; i < innerRing.size(); ++i ) { if ( !poly->outerBoundary().contains( innerRing.at(i) ) ) { return false; } } } return true; } void AreaAnnotation::setupRegionsLists( GeoPainter *painter ) { const GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); const GeoDataLinearRing &outerRing = polygon->outerBoundary(); const QVector &innerRings = polygon->innerBoundaries(); // Add the outer boundary nodes. QVector::ConstIterator itBegin = outerRing.constBegin(); QVector::ConstIterator itEnd = outerRing.constEnd(); m_outerNodesList.clear(); m_innerNodesList.clear(); m_boundariesList.clear(); for ( ; itBegin != itEnd; ++itBegin ) { const PolylineNode newNode = PolylineNode( painter->regionFromEllipse( *itBegin, regularDim, regularDim ) ); m_outerNodesList.append( newNode ); } for ( const GeoDataLinearRing &innerRing: innerRings ) { QVector::ConstIterator itBegin = innerRing.constBegin(); QVector::ConstIterator itEnd = innerRing.constEnd(); QVector innerNodes; innerNodes.reserve(innerRing.size()); for ( ; itBegin != itEnd; ++itBegin ) { const PolylineNode newNode = PolylineNode( painter->regionFromEllipse( *itBegin, regularDim, regularDim ) ); innerNodes.append( newNode ); } m_innerNodesList.append( innerNodes ); } // Add the outer boundary to the boundaries list. m_boundariesList.append( painter->regionFromPolygon( outerRing, Qt::OddEvenFill ) ); } void AreaAnnotation::updateRegions( GeoPainter *painter ) { if ( m_busy ) { return; } const GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); const GeoDataLinearRing &outerRing = polygon->outerBoundary(); const QVector &innerRings = polygon->innerBoundaries(); if ( state() == SceneGraphicsItem::AddingNodes ) { // Create and update virtual nodes lists when being in the AddingPolgonNodes state, to // avoid overhead in other states. m_outerVirtualNodes.clear(); const QRegion firstRegion( painter->regionFromEllipse( outerRing.first().interpolate( outerRing.last(), 0.5 ), hoveredDim, hoveredDim ) ); m_outerVirtualNodes.append( PolylineNode( firstRegion ) ); for ( int i = 0; i < outerRing.size() - 1; ++i ) { const QRegion newRegion( painter->regionFromEllipse( outerRing.at(i).interpolate( outerRing.at(i+1), 0.5 ), hoveredDim, hoveredDim ) ); m_outerVirtualNodes.append( PolylineNode( newRegion ) ); } m_innerVirtualNodes.clear(); m_innerVirtualNodes.reserve(innerRings.size()); for ( int i = 0; i < innerRings.size(); ++i ) { m_innerVirtualNodes.append(QVector()); const QRegion firstRegion( painter->regionFromEllipse( innerRings.at(i).first().interpolate( innerRings.at(i).last(), 0.5 ), hoveredDim, hoveredDim ) ); m_innerVirtualNodes[i].append( PolylineNode( firstRegion ) ); for ( int j = 0; j < innerRings.at(i).size() - 1; ++j ) { const QRegion newRegion( painter->regionFromEllipse( innerRings.at(i).at(j).interpolate( innerRings.at(i).at(j+1), 0.5 ), hoveredDim, hoveredDim ) ); m_innerVirtualNodes[i].append( PolylineNode( newRegion ) ); } } } // Update the boundaries list. m_boundariesList.clear(); m_boundariesList.reserve(1 + innerRings.size()); m_boundariesList.append( painter->regionFromPolygon( outerRing, Qt::OddEvenFill ) ); for ( const GeoDataLinearRing &ring: innerRings ) { m_boundariesList.append( painter->regionFromPolygon( ring, Qt::OddEvenFill ) ); } // Update the outer and inner nodes lists. Q_ASSERT( m_outerNodesList.size() == outerRing.size() ); for ( int i = 0; i < m_outerNodesList.size(); ++i ) { const QRegion newRegion = m_outerNodesList.at(i).isSelected() ? painter->regionFromEllipse( outerRing.at(i), selectedDim, selectedDim ) : painter->regionFromEllipse( outerRing.at(i), regularDim, regularDim ); m_outerNodesList[i].setRegion( newRegion ); } Q_ASSERT( m_innerNodesList.size() == innerRings.size() ); for ( int i = 0; i < m_innerNodesList.size(); ++i ) { Q_ASSERT( m_innerNodesList.at(i).size() == innerRings.at(i).size() ); for ( int j = 0; j < m_innerNodesList.at(i).size(); ++j ) { const QRegion newRegion = m_innerNodesList.at(i).at(j).isSelected() ? painter->regionFromEllipse( innerRings.at(i).at(j), selectedDim, selectedDim ) : painter->regionFromEllipse( innerRings.at(i).at(j), regularDim, regularDim ); m_innerNodesList[i][j].setRegion( newRegion ); } } } void AreaAnnotation::drawNodes( GeoPainter *painter ) { // These are the 'real' dimensions of the drawn nodes. The ones which have class scope are used // to generate the regions and they are a little bit larger, because, for example, it would be // a little bit too hard to select nodes. static const int d_regularDim = 10; static const int d_selectedDim = 10; static const int d_mergedDim = 20; static const int d_hoveredDim = 20; const GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); const GeoDataLinearRing &outerRing = polygon->outerBoundary(); const QVector &innerRings = polygon->innerBoundaries(); QColor glowColor = QApplication::palette().highlightedText().color(); glowColor.setAlpha(120); auto const selectedColor = QApplication::palette().highlight().color(); auto const hoveredColor = selectedColor; for ( int i = 0; i < outerRing.size(); ++i ) { // The order here is important, because a merged node can be at the same time selected. if ( m_outerNodesList.at(i).isBeingMerged() ) { painter->setBrush( mergedColor ); painter->drawEllipse( outerRing.at(i), d_mergedDim, d_mergedDim ); } else if ( m_outerNodesList.at(i).isSelected() ) { painter->setBrush( selectedColor ); painter->drawEllipse( outerRing.at(i), d_selectedDim, d_selectedDim ); if ( m_outerNodesList.at(i).isEditingHighlighted() || m_outerNodesList.at(i).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setBrush( Qt::NoBrush ); painter->setPen( newPen ); painter->drawEllipse( outerRing.at(i), d_selectedDim + 2, d_selectedDim + 2 ); painter->setPen( defaultPen ); } } else { painter->setBrush( regularColor ); painter->drawEllipse( outerRing.at(i), d_regularDim, d_regularDim ); if ( m_outerNodesList.at(i).isEditingHighlighted() || m_outerNodesList.at(i).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setPen( newPen ); painter->setBrush( Qt::NoBrush ); painter->drawEllipse( outerRing.at(i), d_regularDim + 2, d_regularDim + 2 ); painter->setPen( defaultPen ); } } } for ( int i = 0; i < innerRings.size(); ++i ) { for ( int j = 0; j < innerRings.at(i).size(); ++j ) { if ( m_innerNodesList.at(i).at(j).isBeingMerged() ) { painter->setBrush( mergedColor ); painter->drawEllipse( innerRings.at(i).at(j), d_mergedDim, d_mergedDim ); } else if ( m_innerNodesList.at(i).at(j).isSelected() ) { painter->setBrush( selectedColor ); painter->drawEllipse( innerRings.at(i).at(j), d_selectedDim, d_selectedDim ); if ( m_innerNodesList.at(i).at(j).isEditingHighlighted() || m_innerNodesList.at(i).at(j).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setBrush( Qt::NoBrush ); painter->setPen( newPen ); painter->drawEllipse( innerRings.at(i).at(j), d_selectedDim + 2, d_selectedDim + 2 ); painter->setPen( defaultPen ); } } else { painter->setBrush( regularColor ); painter->drawEllipse( innerRings.at(i).at(j), d_regularDim, d_regularDim ); if ( m_innerNodesList.at(i).at(j).isEditingHighlighted() || m_innerNodesList.at(i).at(j).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setBrush( Qt::NoBrush ); painter->setPen( newPen ); painter->drawEllipse( innerRings.at(i).at(j), d_regularDim + 2, d_regularDim + 2 ); painter->setPen( defaultPen ); } } } } if ( m_virtualHovered != QPair( -1, -1 ) ) { const int i = m_virtualHovered.first; const int j = m_virtualHovered.second; painter->setBrush( hoveredColor ); if ( i != -1 && j == -1 ) { const GeoDataCoordinates coords = i ? outerRing.at(i).interpolate( outerRing.at(i - 1), 0.5 ) : outerRing.first().interpolate( outerRing.last(), 0.5 ); painter->drawEllipse( coords, d_hoveredDim, d_hoveredDim ); } else { Q_ASSERT( i != -1 && j != -1 ); const GeoDataCoordinates coords = j ? innerRings.at(i).at(j).interpolate( innerRings.at(i).at(j - 1), 0.5 ) : innerRings.at(i).first().interpolate( innerRings.at(i).last(), 0.5 ); painter->drawEllipse( coords, d_hoveredDim, d_hoveredDim ); } } } int AreaAnnotation::outerNodeContains( const QPoint &point ) const { if ( !hasFocus() ) { return -1; } for ( int i = 0; i < m_outerNodesList.size(); ++i ) { if ( m_outerNodesList.at(i).containsPoint( point ) ) { return i; } } return -1; } QPair AreaAnnotation::innerNodeContains( const QPoint &point ) const { if ( !hasFocus() ) { return QPair( -1, -1 ); } for ( int i = 0; i < m_innerNodesList.size(); ++i ) { for ( int j = 0; j < m_innerNodesList.at(i).size(); ++j ) { if ( m_innerNodesList.at(i).at(j).containsPoint( point ) ) { return QPair( i, j ); } } } return QPair( -1, -1 ); } QPair AreaAnnotation::virtualNodeContains( const QPoint &point ) const { if ( !hasFocus() ) { return QPair( -1, -1 ); } for ( int i = 0; i < m_outerVirtualNodes.size(); ++i ) { if ( m_outerVirtualNodes.at(i).containsPoint( point ) ) { return QPair( i, -1 ); } } for ( int i = 0; i < m_innerVirtualNodes.size(); ++i ) { for ( int j = 0; j < m_innerVirtualNodes.at(i).size(); ++j ) { if ( m_innerVirtualNodes.at(i).at(j).containsPoint( point ) ) { return QPair( i, j ); } } } return QPair( -1, -1 ); } int AreaAnnotation::innerBoundsContain( const QPoint &point ) const { // There are no inner boundaries. if ( m_boundariesList.size() == 1 ) { return -1; } // Starting from 1 because on index 0 is stored the region representing the whole polygon. for ( int i = 1; i < m_boundariesList.size(); ++i ) { if ( m_boundariesList.at(i).contains( point ) ) { return i; } } return -1; } bool AreaAnnotation::polygonContains( const QPoint &point ) const { return m_boundariesList.first().contains( point ); } bool AreaAnnotation::processEditingOnPress( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != Qt::LeftButton && mouseEvent->button() != Qt::RightButton ) { return false; } qreal lat, lon; m_viewport->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); m_movedPointCoords.set( lon, lat ); // First check if one of the nodes from outer boundary has been clicked. const int outerIndex = outerNodeContains( mouseEvent->pos() ); if ( outerIndex != -1 ) { m_clickedNodeIndexes = QPair( outerIndex, -1 ); if ( mouseEvent->button() == Qt::RightButton ) { setRequest( SceneGraphicsItem::ShowNodeRmbMenu ); } else { m_interactingObj = InteractingNode; } return true; } // Then check if one of the nodes which form an inner boundary has been clicked. const QPair innerIndexes = innerNodeContains( mouseEvent->pos() ); if ( innerIndexes.first != -1 && innerIndexes.second != -1 ) { m_clickedNodeIndexes = innerIndexes; if ( mouseEvent->button() == Qt::RightButton ) { setRequest( SceneGraphicsItem::ShowNodeRmbMenu ); } else { m_interactingObj = InteractingNode; } return true; } // If neither outer boundary nodes nor inner boundary nodes contain the event position, // then check if the interior of the polygon (excepting its 'holes') contains this point. if ( polygonContains( mouseEvent->pos() ) && innerBoundsContain( mouseEvent->pos() ) == -1 ) { if ( mouseEvent->button() == Qt::RightButton ) { setRequest( SceneGraphicsItem::ShowPolygonRmbMenu ); } else { m_interactingObj = InteractingPolygon; } return true; } return false; } bool AreaAnnotation::processEditingOnMove( QMouseEvent *mouseEvent ) { if ( !m_viewport ) { return false; } qreal lon, lat; m_viewport->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); const GeoDataCoordinates newCoords( lon, lat ); const qreal deltaLat = lat - m_movedPointCoords.latitude(); const qreal deltaLon = lon - m_movedPointCoords.longitude(); if ( m_interactingObj == InteractingNode ) { GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); GeoDataLinearRing &outerRing = polygon->outerBoundary(); QVector &innerRings = polygon->innerBoundaries(); OsmPlacemarkData *osmData = 0; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); } const int i = m_clickedNodeIndexes.first; const int j = m_clickedNodeIndexes.second; if ( j == -1 ) { // Keeping the osmPlacemarkData synchronized with the geometry if ( osmData ) { osmData->memberReference( -1 ).changeNodeReference( outerRing.at( i ), newCoords ); } outerRing[i] = newCoords; } else { Q_ASSERT( i != -1 && j != -1 ); if ( osmData ) { osmData->memberReference( i ).changeNodeReference( innerRings.at( i ).at( j ), newCoords ); } innerRings[i].at(j) = newCoords; } return true; } else if ( m_interactingObj == InteractingPolygon ) { GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); GeoDataLinearRing outerRing = polygon->outerBoundary(); QVector innerRings = polygon->innerBoundaries(); OsmPlacemarkData *osmData = 0; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); } Quaternion latRectAxis = Quaternion::fromEuler( 0, lon, 0); Quaternion latAxis = Quaternion::fromEuler( -deltaLat, 0, 0); Quaternion lonAxis = Quaternion::fromEuler(0, deltaLon, 0); Quaternion rotAxis = latRectAxis * latAxis * latRectAxis.inverse() * lonAxis; polygon->outerBoundary().clear(); polygon->innerBoundaries().clear(); qreal lonRotated, latRotated; for ( int i = 0; i < outerRing.size(); ++i ) { Quaternion qpos = outerRing.at(i).quaternion(); qpos.rotateAroundAxis(rotAxis); qpos.getSpherical( lonRotated, latRotated ); GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 ); if ( osmData ) { osmData->memberReference( -1 ).changeNodeReference( outerRing.at( i ), movedPoint ); } polygon->outerBoundary().append( movedPoint ); } for ( int i = 0; i < innerRings.size(); ++i ) { GeoDataLinearRing newRing( Tessellate ); for ( int j = 0; j < innerRings.at(i).size(); ++j ) { Quaternion qpos = innerRings.at(i).at(j).quaternion(); qpos.rotateAroundAxis(rotAxis); qpos.getSpherical( lonRotated, latRotated ); GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 ); if ( osmData ) { osmData->memberReference( i ).changeNodeReference( innerRings.at( i ).at( j ) , movedPoint ); } newRing.append( movedPoint ); } polygon->innerBoundaries().append( newRing ); } m_movedPointCoords = newCoords; return true; } else if ( m_interactingObj == InteractingNothing ) { return dealWithHovering( mouseEvent ); } return false; } bool AreaAnnotation::processEditingOnRelease( QMouseEvent *mouseEvent ) { static const int mouseMoveOffset = 1; if ( mouseEvent->button() != Qt::LeftButton ) { return false; } if ( m_interactingObj == InteractingNode ) { qreal x, y; m_viewport->screenCoordinates( m_movedPointCoords.longitude(), m_movedPointCoords.latitude(), x, y ); // The node gets selected only if it is clicked and not moved. if ( qFabs(mouseEvent->pos().x() - x) > mouseMoveOffset || qFabs(mouseEvent->pos().y() - y) > mouseMoveOffset ) { m_interactingObj = InteractingNothing; return true; } const int i = m_clickedNodeIndexes.first; const int j = m_clickedNodeIndexes.second; if ( j == -1 ) { m_outerNodesList[i].setFlag( PolylineNode::NodeIsSelected, !m_outerNodesList[i].isSelected() ); } else { m_innerNodesList[i][j].setFlag ( PolylineNode::NodeIsSelected, !m_innerNodesList.at(i).at(j).isSelected() ); } m_interactingObj = InteractingNothing; return true; } else if ( m_interactingObj == InteractingPolygon ) { // Nothing special happens at polygon release. m_interactingObj = InteractingNothing; return true; } return false; } bool AreaAnnotation::processAddingHoleOnPress( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != Qt::LeftButton ) { return false; } qreal lon, lat; m_viewport->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); const GeoDataCoordinates newCoords( lon, lat ); GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); QVector &innerBounds = polygon->innerBoundaries(); innerBounds.last().append( newCoords ); m_innerNodesList.last().append( PolylineNode() ); return true; } bool AreaAnnotation::processAddingHoleOnMove( QMouseEvent *mouseEvent ) { Q_UNUSED( mouseEvent ); return true; } bool AreaAnnotation::processAddingHoleOnRelease( QMouseEvent *mouseEvent ) { Q_UNUSED( mouseEvent ); return true; } bool AreaAnnotation::processMergingOnPress( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != Qt::LeftButton ) { return false; } GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); GeoDataLinearRing initialOuterRing = polygon->outerBoundary(); OsmPlacemarkData *osmData = 0; OsmPlacemarkData initialOsmData; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); } GeoDataLinearRing &outerRing = polygon->outerBoundary(); QVector &innerRings = polygon->innerBoundaries(); const int outerIndex = outerNodeContains( mouseEvent->pos() ); // If the selected node is an outer boundary node. if ( outerIndex != -1 ) { // If this is the first node selected to be merged. if ( m_firstMergedNode.first == -1 && m_firstMergedNode.second == -1 ) { m_firstMergedNode = QPair( outerIndex, -1 ); m_outerNodesList[outerIndex].setFlag( PolylineNode::NodeIsMerged ); // If the first selected node was an inner boundary node, raise the request for showing // warning. } else if ( m_firstMergedNode.first != -1 && m_firstMergedNode.second != -1 ) { setRequest( SceneGraphicsItem::OuterInnerMergingWarning ); m_innerNodesList[m_firstMergedNode.first][m_firstMergedNode.second].setFlag( PolylineNode::NodeIsMerged, false ); if ( m_hoveredNode.first != -1 ) { // We can be sure that the hovered node is an outer node. Q_ASSERT( m_hoveredNode.second == -1 ); m_outerNodesList[m_hoveredNode.first].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } m_hoveredNode = m_firstMergedNode = QPair( -1, -1 ); } else { Q_ASSERT( m_firstMergedNode.first != -1 && m_firstMergedNode.second == -1 ); // Clicking two times the same node results in unmarking it for merging. if ( m_firstMergedNode.first == outerIndex ) { m_outerNodesList[outerIndex].setFlag( PolylineNode::NodeIsMerged, false ); m_firstMergedNode = QPair( -1, -1 ); return true; } // If two nodes which form a triangle are merged, the whole triangle should be // destroyed. if ( outerRing.size() <= 3 ) { setRequest( SceneGraphicsItem::RemovePolygonRequest ); return true; } GeoDataCoordinates mergedNode = outerRing.at(m_firstMergedNode.first).interpolate( outerRing.at(outerIndex), 0.5 ); // Keeping the osm data synchronized with the geometry if ( osmData ) { osmData->memberReference( -1 ).changeNodeReference( outerRing.at( outerIndex ), mergedNode ); osmData->memberReference( -1 ).removeNodeReference( outerRing.at( m_firstMergedNode.first ) ); } outerRing[outerIndex] = mergedNode; outerRing.remove( m_firstMergedNode.first ); if ( !isValidPolygon() ) { if ( osmData ) { placemark()->setOsmData( initialOsmData ); } polygon->outerBoundary() = initialOuterRing; m_outerNodesList[m_firstMergedNode.first].setFlag( PolylineNode::NodeIsMerged, false ); // Remove highlight effect before showing warning if ( m_hoveredNode.first != -1 ) { m_outerNodesList[m_hoveredNode.first].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } m_hoveredNode = m_firstMergedNode = QPair( -1, -1 ); setRequest( SceneGraphicsItem::InvalidShapeWarning ); return true; } // Do not modify it here. The animation has access to the object. It will modify the polygon. polygon->outerBoundary() = initialOuterRing; m_outerNodesList[outerIndex].setFlag( PolylineNode::NodeIsMerged ); m_secondMergedNode = QPair( outerIndex, -1 ); delete m_animation; m_animation = new MergingPolygonNodesAnimation( this ); setRequest( SceneGraphicsItem::StartPolygonAnimation ); } return true; } // If the selected node is an inner boundary node. const QPair innerIndexes = innerNodeContains( mouseEvent->pos() ); if ( innerIndexes.first != -1 && innerIndexes.second != -1 ) { const int i = m_firstMergedNode.first; const int j = m_firstMergedNode.second; // If this is the first selected node. if ( i == -1 && j == -1 ) { m_firstMergedNode = innerIndexes; m_innerNodesList[innerIndexes.first][innerIndexes.second].setFlag( PolylineNode::NodeIsMerged ); // If the first selected node has been an outer boundary one, raise the request for showing warning. } else if ( i != -1 && j == -1 ) { setRequest( SceneGraphicsItem::OuterInnerMergingWarning ); m_outerNodesList[i].setFlag( PolylineNode::NodeIsMerged, false ); if ( m_hoveredNode.first != -1 ) { // We can now be sure that the highlighted node is a node from polygon's outer boundary Q_ASSERT( m_hoveredNode.second != -1 ); m_outerNodesList[m_hoveredNode.first].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } m_firstMergedNode = QPair( -1, -1 ); } else { Q_ASSERT( i != -1 && j != -1 ); if ( i != innerIndexes.first ) { setRequest( SceneGraphicsItem::InnerInnerMergingWarning ); m_innerNodesList[i][j].setFlag( PolylineNode::NodeIsMerged, false ); if ( m_hoveredNode.first != -1 && m_hoveredNode.second != -1 ) { m_innerNodesList[m_hoveredNode.first][m_hoveredNode.second].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } m_hoveredNode = m_firstMergedNode = QPair( -1, -1 ); return true; } // Clicking two times the same node results in unmarking it for merging. if ( m_firstMergedNode == innerIndexes ) { m_innerNodesList[i][j].setFlag( PolylineNode::NodeIsMerged, false ); m_firstMergedNode = QPair( -1, -1 ); return true; } // If two nodes which form an inner boundary of a polygon with a size smaller than // 3 are merged, remove the whole inner boundary. if ( innerRings.at(i).size() <= 3 ) { innerRings.remove( i ); m_innerNodesList.removeAt( i ); m_firstMergedNode = m_secondMergedNode = m_hoveredNode = QPair( -1, -1 ); return true; } m_innerNodesList[innerIndexes.first][innerIndexes.second].setFlag( PolylineNode::NodeIsMerged ); m_secondMergedNode = innerIndexes; m_animation = new MergingPolygonNodesAnimation( this ); setRequest( SceneGraphicsItem::StartPolygonAnimation ); } return true; } return false; } bool AreaAnnotation::processMergingOnMove( QMouseEvent *mouseEvent ) { return dealWithHovering( mouseEvent ); } bool AreaAnnotation::processMergingOnRelease( QMouseEvent *mouseEvent ) { Q_UNUSED( mouseEvent ); return true; } bool AreaAnnotation::processAddingNodesOnPress( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != Qt::LeftButton ) { return false; } GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); GeoDataLinearRing &outerRing = polygon->outerBoundary(); QVector &innerRings = polygon->innerBoundaries(); // If a virtual node has just been clicked, add it to the polygon's outer boundary // and start 'adjusting' its position. const QPair index = virtualNodeContains( mouseEvent->pos() ); if ( index != QPair( -1, -1 ) && m_adjustedNode == -2 ) { Q_ASSERT( m_virtualHovered == index ); const int i = index.first; const int j = index.second; if ( i != -1 && j == -1 ) { GeoDataLinearRing newRing( Tessellate ); QVector newList; newList.reserve(outerRing.size()); for ( int k = i; k < i + outerRing.size(); ++k ) { newRing.append( outerRing.at(k % outerRing.size()) ); PolylineNode newNode; newNode.setFlags( m_outerNodesList.at(k % outerRing.size()).flags() ); newList.append( newNode ); } GeoDataCoordinates newCoords = newRing.first().interpolate( newRing.last(), 0.5 ); newRing.append( newCoords ); m_outerNodesList = newList; m_outerNodesList.append( PolylineNode( QRegion() ) ); polygon->outerBoundary() = newRing; m_adjustedNode = -1; } else { Q_ASSERT( i != -1 && j != -1 ); GeoDataLinearRing newRing( Tessellate ); QVector newList; newList.reserve(innerRings.at(i).size()); for ( int k = j; k < j + innerRings.at(i).size(); ++k ) { newRing.append( innerRings.at(i).at(k % innerRings.at(i).size()) ); PolylineNode newNode; newNode.setFlags( m_innerNodesList.at(i).at(k % innerRings.at(i).size()).flags() ); newList.append( newNode ); } GeoDataCoordinates newCoords = newRing.first().interpolate( newRing.last(), 0.5 ); newRing.append( newCoords ); m_innerNodesList[i] = newList; m_innerNodesList[i].append( PolylineNode( QRegion() ) ); polygon->innerBoundaries()[i] = newRing; m_adjustedNode = i; } m_virtualHovered = QPair( -1, -1 ); return true; } // If a virtual node which has been previously clicked and selected to become a // 'real node' is clicked one more time, it stops from being 'adjusted'. const int outerIndex = outerNodeContains( mouseEvent->pos() ); if ( outerIndex != -1 && m_adjustedNode != -2 ) { m_adjustedNode = -2; return true; } const QPair innerIndex = innerNodeContains( mouseEvent->pos() ); if ( innerIndex != QPair( -1, -1 ) && m_adjustedNode != -2 ) { m_adjustedNode = -2; return true; } return false; } bool AreaAnnotation::processAddingNodesOnMove( QMouseEvent *mouseEvent ) { Q_ASSERT( mouseEvent->button() == Qt::NoButton ); const QPair index = virtualNodeContains( mouseEvent->pos() ); // If we are adjusting a virtual node which has just been clicked and became real, just // change its coordinates when moving it, as we do with nodes in Editing state on move. if ( m_adjustedNode != -2 ) { // The virtual node which has just been added is always the last within // GeoDataLinearRing's container.qreal lon, lat; qreal lon, lat; m_viewport->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); const GeoDataCoordinates newCoords( lon, lat ); GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); if ( m_adjustedNode == -1 ) { polygon->outerBoundary().last() = newCoords; } else { Q_ASSERT( m_adjustedNode >= 0 ); polygon->innerBoundaries()[m_adjustedNode].last() = newCoords; } return true; // If we are hovering a virtual node, store its index in order to be painted in drawNodes // method. } else if ( index != QPair( -1, -1 ) ) { m_virtualHovered = index; return true; } // This means that the interior of the polygon has been hovered. Let the event propagate // since there may be overlapping polygons. return false; } bool AreaAnnotation::processAddingNodesOnRelease( QMouseEvent *mouseEvent ) { Q_UNUSED( mouseEvent ); return m_adjustedNode == -2; } bool AreaAnnotation::dealWithHovering( QMouseEvent *mouseEvent ) { const PolylineNode::PolyNodeFlag flag = state() == SceneGraphicsItem::Editing ? PolylineNode::NodeIsEditingHighlighted : PolylineNode::NodeIsMergingHighlighted; const int outerIndex = outerNodeContains( mouseEvent->pos() ); if ( outerIndex != -1 ) { if ( !m_outerNodesList.at(outerIndex).isEditingHighlighted() && !m_outerNodesList.at(outerIndex).isMergingHighlighted() ) { // Deal with the case when two nodes are very close to each other. if ( m_hoveredNode != QPair( -1, -1 ) ) { const int i = m_hoveredNode.first; const int j = m_hoveredNode.second; if ( j == -1 ) { m_outerNodesList[i].setFlag( flag, false ); } else { m_innerNodesList[i][j].setFlag( flag, false ); } } m_hoveredNode = QPair( outerIndex, -1 ); m_outerNodesList[outerIndex].setFlag( flag ); setRequest( ChangeCursorPolygonNodeHover ); } return true; } else if ( m_hoveredNode != QPair( -1, -1 ) && m_hoveredNode.second == -1 ) { m_outerNodesList[m_hoveredNode.first].setFlag( flag, false ); m_hoveredNode = QPair( -1, -1 ); return true; } const QPair innerIndex = innerNodeContains( mouseEvent->pos() ); if ( innerIndex != QPair( -1, -1 ) ) { if ( !m_innerNodesList.at(innerIndex.first).at(innerIndex.second).isEditingHighlighted() && !m_innerNodesList.at(innerIndex.first).at(innerIndex.second).isMergingHighlighted()) { // Deal with the case when two nodes are very close to each other. if ( m_hoveredNode != QPair( -1, -1 ) ) { const int i = m_hoveredNode.first; const int j = m_hoveredNode.second; if ( j == -1 ) { m_outerNodesList[i].setFlag( flag, false ); } else { m_innerNodesList[i][j].setFlag( flag, false ); } } m_hoveredNode = innerIndex; m_innerNodesList[innerIndex.first][innerIndex.second].setFlag( flag ); setRequest( ChangeCursorPolygonNodeHover ); } return true; } else if ( m_hoveredNode != QPair( -1, -1 ) && m_hoveredNode.second != -1 ) { m_innerNodesList[m_hoveredNode.first][m_hoveredNode.second].setFlag( flag, false ); m_hoveredNode = QPair( -1, -1 ); return true; } // This means that the interior of the polygon has been covered so we catch this event too. setRequest( ChangeCursorPolygonBodyHover ); return true; } } diff --git a/src/plugins/render/annotate/EditPolygonDialog.cpp b/src/plugins/render/annotate/EditPolygonDialog.cpp index 487c525fc..317637bc6 100644 --- a/src/plugins/render/annotate/EditPolygonDialog.cpp +++ b/src/plugins/render/annotate/EditPolygonDialog.cpp @@ -1,346 +1,342 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Calin Cruceru // // Self #include "EditPolygonDialog.h" #include "ui_EditPolygonDialog.h" // Qt #include #include // Marble #include "GeoDataPlacemark.h" #include "GeoDataStyle.h" #include "GeoDataLineStyle.h" #include "GeoDataPolyStyle.h" -#include "GeoDataTypes.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" #include "NodeModel.h" #include "NodeItemDelegate.h" #include "FormattedTextWidget.h" #include "StyleBuilder.h" #include "osm/OsmTagEditorWidget.h" #include "osm/OsmPlacemarkData.h" #include "osm/OsmRelationManagerWidget.h" namespace Marble { class Q_DECL_HIDDEN EditPolygonDialog::Private : public Ui::UiEditPolygonDialog { public: Private( GeoDataPlacemark *placemark ); ~Private(); GeoDataPlacemark *m_placemark; QColorDialog *m_linesDialog; QColorDialog *m_polyDialog; QString m_initialDescription; QString m_initialName; GeoDataStyle m_initialStyle; GeoDataLinearRing m_initialOuterBoundary; OsmPlacemarkData m_initialOsmData; bool m_hadInitialOsmData; NodeModel *m_nodeModel; NodeItemDelegate *m_delegate; OsmTagEditorWidget *m_osmTagEditorWidget; OsmRelationManagerWidget *m_osmRelationManagerWidget; }; EditPolygonDialog::Private::Private( GeoDataPlacemark *placemark ) : Ui::UiEditPolygonDialog(), m_placemark( placemark ), m_linesDialog( 0 ), m_polyDialog( 0 ), m_nodeModel( new NodeModel ), m_osmTagEditorWidget( 0 ), m_osmRelationManagerWidget( 0 ) { // nothing to do } EditPolygonDialog::Private::~Private() { delete m_linesDialog; delete m_polyDialog; delete m_nodeModel; delete m_delegate; } EditPolygonDialog::EditPolygonDialog( GeoDataPlacemark *placemark, const QHash *relations, QWidget *parent ) : QDialog( parent ), d( new Private( placemark ) ) { d->setupUi( this ); // There's no point showing Relations and Tags tabs if the editor was not // loaded from the annotate plugin ( loaded from tourWidget.. ) if ( relations ) { // Adding the osm tag editor widget tab d->m_osmTagEditorWidget = new OsmTagEditorWidget( placemark, this ); d->tabWidget->addTab( d->m_osmTagEditorWidget, tr( "Tags" ) ); QObject::connect( d->m_osmTagEditorWidget, SIGNAL( placemarkChanged( GeoDataFeature* ) ), this, SLOT( updatePolygon() ) ); // Adding the osm relation editor widget tab d->m_osmRelationManagerWidget = new OsmRelationManagerWidget( placemark, relations, this ); d->tabWidget->addTab( d->m_osmRelationManagerWidget, tr( "Relations" ) ); QObject::connect( d->m_osmRelationManagerWidget, SIGNAL( relationCreated( const OsmPlacemarkData& ) ), this, SIGNAL( relationCreated( const OsmPlacemarkData& ) ) ); adjustSize(); } d->m_hadInitialOsmData = placemark->hasOsmData(); if ( d->m_hadInitialOsmData ) { d->m_initialOsmData = placemark->osmData(); } d->m_initialStyle = *placemark->style(); // If the polygon has just been drawn, assign it a default name. if ( d->m_placemark->name().isNull() ) { d->m_placemark->setName( tr("Untitled Polygon") ); } d->m_name->setText( placemark->name() ); d->m_initialName = placemark->name(); connect( d->m_name, SIGNAL(editingFinished()), this, SLOT(updatePolygon()) ); d->m_formattedTextWidget->setText( placemark->description() ); d->m_initialDescription = placemark->description(); // Get the current style properties. const GeoDataLineStyle lineStyle = placemark->style()->lineStyle(); const GeoDataPolyStyle polyStyle = placemark->style()->polyStyle(); d->m_linesWidth->setRange( 0.1, 5.0 ); d->m_linesWidth->setValue( lineStyle.width() ); connect( d->m_linesWidth, SIGNAL(valueChanged(double)), this, SLOT( handleChangingStyle() ) ); // Adjust the "Filled"/"Not Filled" option according to its current fill. if ( polyStyle.fill() ) { d->m_filledColor->setCurrentIndex( 0 ); } else { d->m_filledColor->setCurrentIndex( 1 ); } connect( d->m_filledColor, SIGNAL(currentIndexChanged(int)), this, SLOT( handleChangingStyle() ) ); // Adjust the color buttons' icons to the current lines and polygon colors. QPixmap linesPixmap( d->m_linesColorButton->iconSize().width(), d->m_linesColorButton->iconSize().height() ); linesPixmap.fill( lineStyle.color() ); d->m_linesColorButton->setIcon( QIcon( linesPixmap ) ); QPixmap polyPixmap( d->m_polyColorButton->iconSize().width(), d->m_polyColorButton->iconSize().height() ); polyPixmap.fill( polyStyle.color() ); d->m_polyColorButton->setIcon( QIcon( polyPixmap ) ); // Setup the color dialogs. d->m_linesDialog = new QColorDialog( this ); d->m_linesDialog->setOption( QColorDialog::ShowAlphaChannel ); d->m_linesDialog->setCurrentColor( lineStyle.color() ); connect( d->m_linesColorButton, SIGNAL(clicked()), d->m_linesDialog, SLOT(exec()) ); connect( d->m_linesDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateLinesDialog(QColor)) ); connect( d->m_linesDialog, SIGNAL(colorSelected(QColor)), this, SLOT( handleChangingStyle() ) ); d->m_polyDialog = new QColorDialog( this ); d->m_polyDialog->setOption( QColorDialog::ShowAlphaChannel ); d->m_polyDialog->setCurrentColor( polyStyle.color() ); connect( d->m_polyColorButton, SIGNAL(clicked()), d->m_polyDialog, SLOT(exec()) ); connect( d->m_polyDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updatePolyDialog(QColor)) ); connect( d->m_polyDialog, SIGNAL(colorSelected(QColor)), this, SLOT( handleChangingStyle() ) ); // Setting the NodeView's delegate: mainly used for the editing the polygon's nodes d->m_delegate = new NodeItemDelegate( d->m_placemark, d->m_nodeView ); connect( d->m_delegate, SIGNAL(modelChanged(GeoDataPlacemark*)), this, SLOT(handleItemMoving(GeoDataPlacemark*)) ); connect( d->m_delegate, SIGNAL(geometryChanged()), this, SLOT(updatePolygon()) ); d->m_nodeView->setItemDelegate( d->m_delegate ); d->m_nodeView->setEditTriggers( QAbstractItemView::AllEditTriggers ); // Populating the model - if( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { - GeoDataPolygon *polygon = static_cast( placemark->geometry() ); + if (const GeoDataPolygon *polygon = geodata_cast(placemark->geometry())) { GeoDataLinearRing outerBoundary = polygon->outerBoundary(); for( int i = 0; i < outerBoundary.size(); ++i ) { d->m_nodeModel->addNode( outerBoundary.at( i ) ); } d->m_initialOuterBoundary = outerBoundary; } d->m_nodeView->setModel( d->m_nodeModel ); // Resize column to contents size for better UI. d->m_nodeView->resizeColumnToContents( 0 ); // Promote "Ok" button to default button. d->buttonBox->button( QDialogButtonBox::Ok )->setDefault( true ); connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(pressed()), this, SLOT(checkFields()) ); connect( this, SIGNAL(accepted()), SLOT(updatePolygon()) ); connect( this, SIGNAL(finished(int)), SLOT(restoreInitial(int)) ); // Ensure that the dialog gets deleted when closing it (either when clicking OK or // Close). connect( this, SIGNAL(finished(int)), SLOT(deleteLater()) ); } EditPolygonDialog::~EditPolygonDialog() { delete d; } void EditPolygonDialog::handleAddingNode( const GeoDataCoordinates &node ) { d->m_nodeModel->addNode( node ); } void EditPolygonDialog::handleItemMoving( GeoDataPlacemark *item ) { if( item == d->m_placemark ) { d->m_nodeModel->clear(); - if( d->m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { - GeoDataPolygon *polygon = static_cast( d->m_placemark->geometry() ); + if (const auto polygon = geodata_cast(d->m_placemark->geometry())) { GeoDataLinearRing outerBoundary = polygon->outerBoundary(); for( int i = 0; i < outerBoundary.size(); ++i ) { d->m_nodeModel->addNode( outerBoundary.at( i ) ); } } } } void EditPolygonDialog::handleChangingStyle() { // The default style of the polygon has been changed, thus the old style URL is no longer valid d->m_placemark->setStyleUrl(QString()); GeoDataStyle::Ptr style(new GeoDataStyle( *d->m_placemark->style() )); style->lineStyle().setWidth( d->m_linesWidth->value() ); // 0 corresponds to "Filled" and 1 corresponds to "Not Filled". style->polyStyle().setFill( !d->m_filledColor->currentIndex() ); style->setId(d->m_placemark->id() + QLatin1String("Style")); // Adjust the lines/polygon colors. // QColorDialog::currentColor() also works even if the color dialog // has not been exec'ed, while QColorDialog::selectedColor() does not. style->lineStyle().setColor( d->m_linesDialog->currentColor() ); style->polyStyle().setColor( d->m_polyDialog->currentColor() ); d->m_placemark->setStyle( style ); updatePolygon(); } void EditPolygonDialog::updatePolygon() { d->m_placemark->setName( d->m_name->text() ); d->m_placemark->setDescription( d->m_formattedTextWidget->text() ); // If there is not custom style initialized( default #polyline url is used ) and there is a osmTag-based style // available, set it const OsmPlacemarkData osmData = d->m_osmTagEditorWidget->placemarkData(); const GeoDataPlacemark::GeoDataVisualCategory category = StyleBuilder::determineVisualCategory(osmData); if (d->m_placemark->styleUrl() == QLatin1String("#polygon") && category != GeoDataPlacemark::None) { d->m_placemark->setStyle( GeoDataStyle::Ptr() ); // first clear style so style gets set by setVisualCategory() d->m_placemark->setVisualCategory( category ); } emit polygonUpdated( d->m_placemark ); } void EditPolygonDialog::updateLinesDialog( const QColor &color ) { QPixmap linesPixmap( d->m_linesColorButton->iconSize().width(), d->m_linesColorButton->iconSize().height() ); linesPixmap.fill( color ); d->m_linesColorButton->setIcon( QIcon( linesPixmap ) ); } void EditPolygonDialog::updatePolyDialog( const QColor &color ) { QPixmap polyPixmap( d->m_polyColorButton->iconSize().width(), d->m_polyColorButton->iconSize().height() ); polyPixmap.fill( color ); d->m_polyColorButton->setIcon( QIcon( polyPixmap ) ); } void EditPolygonDialog::checkFields() { bool ok = true; if ( d->m_name->text().isEmpty() ) { QMessageBox::warning( this, tr( "No name specified" ), tr( "Please specify a name for this polygon." ) ); ok = false; } else { - if ( d->m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { - GeoDataPolygon *polygon = static_cast( d->m_placemark->geometry() ); + if (const auto polygon = geodata_cast(d->m_placemark->geometry())) { if( polygon->outerBoundary().size() < 3 ) { QMessageBox::warning( this, tr( "Not enough nodes specified." ), tr( "Please specify at least 3 nodes for the polygon by clicking on the map." ) ); ok = false; } } } if( ok ) { accept(); } } void EditPolygonDialog::restoreInitial( int result ) { if ( result ) { return; } GeoDataPolygon *polygon = static_cast( d->m_placemark->geometry() ); GeoDataLinearRing outerBoundary = polygon->outerBoundary(); if ( outerBoundary != d->m_initialOuterBoundary ) { polygon->setOuterBoundary( d->m_initialOuterBoundary ); } if ( d->m_placemark->name() != d->m_initialName ) { d->m_placemark->setName( d->m_initialName ); } if ( d->m_placemark->description() != d->m_initialDescription ) { d->m_placemark->setDescription( d->m_initialDescription ); } if ( *d->m_placemark->style() != d->m_initialStyle ) { d->m_placemark->setStyle( GeoDataStyle::Ptr(new GeoDataStyle( d->m_initialStyle )) ); } if( d->m_hadInitialOsmData ) { d->m_placemark->setOsmData( d->m_initialOsmData ); } emit polygonUpdated( d->m_placemark ); } } #include "moc_EditPolygonDialog.cpp" diff --git a/src/plugins/render/annotate/EditPolylineDialog.cpp b/src/plugins/render/annotate/EditPolylineDialog.cpp index 43155cccc..79af4dd91 100644 --- a/src/plugins/render/annotate/EditPolylineDialog.cpp +++ b/src/plugins/render/annotate/EditPolylineDialog.cpp @@ -1,302 +1,298 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Calin Cruceru // // Self #include "EditPolylineDialog.h" #include "ui_EditPolylineDialog.h" // Qt #include #include // Marble #include "GeoDataPlacemark.h" #include "GeoDataLineString.h" #include "GeoDataStyle.h" #include "GeoDataLineStyle.h" -#include "GeoDataTypes.h" #include "NodeModel.h" #include "FormattedTextWidget.h" #include "NodeItemDelegate.h" #include "StyleBuilder.h" #include "osm/OsmTagEditorWidget.h" #include "osm/OsmPlacemarkData.h" #include "osm/OsmRelationManagerWidget.h" namespace Marble { class Q_DECL_HIDDEN EditPolylineDialog::Private : public Ui::UiEditPolylineDialog { public: Private( GeoDataPlacemark *placemark); ~Private(); QColorDialog *m_linesDialog; OsmTagEditorWidget *m_osmTagEditorWidget; OsmRelationManagerWidget *m_osmRelationManagerWidget; GeoDataPlacemark *m_placemark; // Used to restore if the Cancel button is pressed. QString m_initialName; QString m_initialDescription; GeoDataLineStyle m_initialLineStyle; GeoDataLineString m_initialLineString; OsmPlacemarkData m_initialOsmData; bool m_hadInitialOsmData; NodeItemDelegate *m_delegate; NodeModel *m_nodeModel; }; EditPolylineDialog::Private::Private( GeoDataPlacemark *placemark ) : Ui::UiEditPolylineDialog(), m_linesDialog( 0 ), m_osmTagEditorWidget( 0 ), m_osmRelationManagerWidget( 0 ), m_placemark( placemark ), m_nodeModel( new NodeModel ) { // nothing to do } EditPolylineDialog::Private::~Private() { delete m_linesDialog; delete m_nodeModel; delete m_delegate; } EditPolylineDialog::EditPolylineDialog( GeoDataPlacemark *placemark, const QHash *relations, QWidget *parent ) : QDialog( parent ) , d ( new Private( placemark ) ) { d->setupUi( this ); // There's no point showing Relations and Tags tabs if the editor was not // loaded from the annotate plugin ( loaded from tourWidget.. ) if ( relations ) { // Adding the osm tag editor widget tab d->m_osmTagEditorWidget = new OsmTagEditorWidget( placemark, this ); d->tabWidget->addTab( d->m_osmTagEditorWidget, tr( "Tags" ) ); QObject::connect( d->m_osmTagEditorWidget, SIGNAL( placemarkChanged( GeoDataFeature* ) ), this, SLOT( updatePolyline() ) ); // Adding the osm relation editor widget tab d->m_osmRelationManagerWidget = new OsmRelationManagerWidget( placemark, relations, this ); d->tabWidget->addTab( d->m_osmRelationManagerWidget, tr( "Relations" ) ); QObject::connect( d->m_osmRelationManagerWidget, SIGNAL( relationCreated( const OsmPlacemarkData& ) ), this, SIGNAL( relationCreated( const OsmPlacemarkData& ) ) ); adjustSize(); } d->m_hadInitialOsmData = placemark->hasOsmData(); if ( d->m_hadInitialOsmData ) { d->m_initialOsmData = placemark->osmData(); } // If the polygon has just been drawn, assign it a default name. if ( d->m_placemark->name().isNull() ) { d->m_placemark->setName( tr("Untitled Path") ); } d->m_initialLineString = *(static_cast( placemark->geometry() ) ); d->m_name->setText( placemark->name() ); d->m_initialName = d->m_name->text(); connect( d->m_name, SIGNAL(editingFinished()), this, SLOT(updatePolyline()) ); d->m_formattedTextWidget->setText( placemark->description() ); d->m_initialDescription = d->m_formattedTextWidget->text(); d->m_linesWidth->setRange( 0.1, 5.0 ); // Get the current style properties. const GeoDataLineStyle lineStyle = placemark->style()->lineStyle(); d->m_initialLineStyle = lineStyle; d->m_linesWidth->setValue( lineStyle.width() ); connect( d->m_linesWidth, SIGNAL(valueChanged(double)), this, SLOT(handleChangingStyle()) ); // Adjust the color button's icon to the current lines color. QPixmap linesPixmap( d->m_linesColorButton->iconSize() ); linesPixmap.fill( lineStyle.color() ); d->m_linesColorButton->setIcon( QIcon( linesPixmap ) ); // Setting the NodeView's delegate: mainly used for the editing the polyline's nodes d->m_delegate = new NodeItemDelegate( d->m_placemark, d->m_nodeView ); connect( d->m_delegate, SIGNAL(modelChanged(GeoDataPlacemark*)), this, SLOT(handleItemMoving(GeoDataPlacemark*)) ); connect( d->m_delegate, SIGNAL(geometryChanged()), this, SLOT(updatePolyline()) ); d->m_nodeView->setItemDelegate( d->m_delegate ); d->m_nodeView->setEditTriggers( QAbstractItemView::AllEditTriggers ); // Setup the color dialogs. d->m_linesDialog = new QColorDialog( this ); d->m_linesDialog->setOption( QColorDialog::ShowAlphaChannel ); d->m_linesDialog->setCurrentColor( lineStyle.color() ); connect( d->m_linesColorButton, SIGNAL(clicked()), d->m_linesDialog, SLOT(exec()) ); connect( d->m_linesDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateLinesDialog(QColor)) ); connect( d->m_linesDialog, SIGNAL(colorSelected(QColor)), this, SLOT(handleChangingStyle()) ); - if( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { - GeoDataLineString *lineString = static_cast( placemark->geometry() ); + if (const auto lineString = geodata_cast(placemark->geometry())) { for( int i = 0; i < lineString->size(); ++i ) { d->m_nodeModel->addNode( lineString->at( i ) ); } } d->m_nodeView->setModel( d->m_nodeModel ); // Resize column to contents size for better UI. d->m_nodeView->resizeColumnToContents( 0 ); // Promote "Ok" button to default button. d->buttonBox->button( QDialogButtonBox::Ok )->setDefault( true ); connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(pressed()), this, SLOT(checkFields()) ); connect( this, SIGNAL(accepted()), SLOT(updatePolyline()) ); connect( this, SIGNAL(finished(int)), SLOT(restoreInitial(int)) ); // Ensure that the dialog gets deleted when closing it (either when clicking OK or // Close). connect( this, SIGNAL(finished(int)), SLOT(deleteLater()) ); } EditPolylineDialog::~EditPolylineDialog() { delete d; } void EditPolylineDialog::handleAddingNode( const GeoDataCoordinates &node ) { d->m_nodeModel->addNode( node ); } void EditPolylineDialog::handleItemMoving( GeoDataPlacemark *item ) { if( item == d->m_placemark ) { d->m_nodeModel->clear(); - if( d->m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { - GeoDataLineString *lineString = static_cast( d->m_placemark->geometry() ); + if (const auto lineString = geodata_cast(d->m_placemark->geometry())) { for( int i = 0; i < lineString->size(); ++i ) { d->m_nodeModel->addNode( lineString->at( i ) ); } } } } void EditPolylineDialog::handleChangingStyle() { // The default style has been changed, thus the old style URL is no longer valid // The polyline is now considered to have a customStyle d->m_placemark->setStyleUrl(QString()); GeoDataStyle::Ptr newStyle(new GeoDataStyle( *d->m_placemark->style() )); newStyle->lineStyle().setColor( d->m_linesDialog->currentColor() ); newStyle->lineStyle().setWidth( d->m_linesWidth->value() ); newStyle->setId(d->m_placemark->id() + QLatin1String("Style")); d->m_placemark->setStyle( newStyle ); updatePolyline(); } void EditPolylineDialog::updatePolyline() { d->m_placemark->setDescription( d->m_formattedTextWidget->text() ); d->m_placemark->setName( d->m_name->text() ); // If there is no custom style initialized( default #polyline url is used ) and there is a osmTag-based style // available, set it const OsmPlacemarkData osmData = d->m_osmTagEditorWidget->placemarkData(); const GeoDataPlacemark::GeoDataVisualCategory category = StyleBuilder::determineVisualCategory(osmData); if (d->m_placemark->styleUrl() == QLatin1String("#polyline") && category != GeoDataPlacemark::None) { d->m_placemark->setStyle( GeoDataStyle::Ptr() ); // first clear style so style gets set by setVisualCategory() d->m_placemark->setVisualCategory( category ); } emit polylineUpdated( d->m_placemark ); } void EditPolylineDialog::updateLinesDialog( const QColor &color ) { QPixmap linesPixmap( d->m_linesColorButton->iconSize().width(), d->m_linesColorButton->iconSize().height() ); linesPixmap.fill( color ); d->m_linesColorButton->setIcon( QIcon( linesPixmap ) ); } void EditPolylineDialog::restoreInitial( int result ) { if ( result ) { return; } GeoDataLineString* currentLineString = static_cast( d->m_placemark->geometry() ); if( *currentLineString != d->m_initialLineString ) { d->m_placemark->setGeometry( new GeoDataLineString( d->m_initialLineString ) ); } if ( d->m_placemark->name() != d->m_initialName ) { d->m_placemark->setName( d->m_initialName ); } if ( d->m_placemark->description() != d->m_initialDescription ) { d->m_placemark->setDescription( d->m_initialDescription ); } if ( d->m_placemark->style()->lineStyle() != d->m_initialLineStyle ) { GeoDataStyle::Ptr newStyle(new GeoDataStyle( *d->m_placemark->style() )); newStyle->setLineStyle( d->m_initialLineStyle ); d->m_placemark->setStyle( newStyle ); } if( d->m_hadInitialOsmData ) { d->m_placemark->setOsmData( d->m_initialOsmData ); } emit polylineUpdated( d->m_placemark ); } void EditPolylineDialog::checkFields() { bool ok = true; if ( d->m_name->text().isEmpty() ) { QMessageBox::warning( this, tr( "No name specified" ), tr( "Please specify a name for this polyline." ) ); ok = false; } else { - if ( d->m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { - GeoDataLineString *lineString = static_cast( d->m_placemark->geometry() ); + if (const auto lineString = geodata_cast(d->m_placemark->geometry())) { if( lineString->size() < 2 ) { QMessageBox::warning( this, tr( "Not enough nodes specified." ), tr( "Please specify at least 2 nodes for the path by clicking on the map." ) ); ok = false; } } } if( ok ) { accept(); } } } #include "moc_EditPolylineDialog.cpp" diff --git a/src/plugins/render/annotate/GroundOverlayFrame.cpp b/src/plugins/render/annotate/GroundOverlayFrame.cpp index 030beff56..3cd29d748 100644 --- a/src/plugins/render/annotate/GroundOverlayFrame.cpp +++ b/src/plugins/render/annotate/GroundOverlayFrame.cpp @@ -1,404 +1,402 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2013 Adrian Draghici // // Self #include "GroundOverlayFrame.h" // Marble #include "GeoDataPlacemark.h" #include "GeoDataGroundOverlay.h" -#include "GeoDataTypes.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" #include "GeoPainter.h" #include "ViewportParams.h" #include "SceneGraphicsTypes.h" #include "TextureLayer.h" #include "MarbleDirs.h" // Qt #include namespace Marble { GroundOverlayFrame::GroundOverlayFrame( GeoDataPlacemark *placemark, GeoDataGroundOverlay *overlay, TextureLayer *textureLayer ) : SceneGraphicsItem( placemark ), m_overlay( overlay ), m_textureLayer( textureLayer ), m_movedHandle( NoRegion ), m_hoveredHandle( NoRegion ), m_editStatus( Resize ), m_editStatusChangeNeeded( false ), m_previousRotation( 0.0 ), m_viewport( 0 ) { m_resizeIcons.reserve(16); // NorthWest m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-diagonal-topleft.png"))); m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-diagonal-topleft-active.png"))); // SouthWest m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-diagonal-topright.png"))); m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-diagonal-topright-active.png"))); // SouthEast m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-diagonal-topleft.png"))); m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-diagonal-topleft-active.png"))); // NorthEast m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-diagonal-topright.png"))); m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-diagonal-topright-active.png"))); // North m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-vertical.png"))); m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-vertical-active.png"))); // South m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-vertical.png"))); m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-vertical-active.png"))); // East m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-horizontal.png"))); m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-horizontal-active.png"))); // West m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-horizontal.png"))); m_resizeIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-horizontal-active.png"))); m_rotateIcons.reserve(16); // NorthWest m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-rotation-topleft.png"))); m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-rotation-topleft-active.png"))); // SouthWest m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-rotation-bottomleft.png"))); m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-rotation-bottomleft-active.png"))); // SouthEast m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-rotation-bottomright.png"))); m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-rotation-bottomright-active.png"))); // NorthEast m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-rotation-topright.png"))); m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-rotation-topright-active.png"))); // North m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-horizontal.png"))); m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-horizontal-active.png"))); // South m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-horizontal.png"))); m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-horizontal-active.png"))); // East m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-vertical.png"))); m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-vertical-active.png"))); // West m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-vertical.png"))); m_rotateIcons.append(QImage(MarbleDirs::systemPath() + QLatin1String("/bitmaps/editarrows/arrow-vertical-active.png"))); update(); setPaintLayers(QStringList() << "GroundOverlayFrame"); } void GroundOverlayFrame::paint(GeoPainter *painter, const ViewportParams *viewport , const QString &layer, int tileZoomLevel) { Q_UNUSED(layer); Q_UNUSED(tileZoomLevel); m_viewport = viewport; m_regionList.clear(); painter->save(); - if ( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { - GeoDataPolygon *polygon = static_cast( placemark()->geometry() ); - GeoDataLinearRing &ring = polygon->outerBoundary(); + if (const auto polygon = geodata_cast(placemark()->geometry())) { + const GeoDataLinearRing &ring = polygon->outerBoundary(); QVector coordinateList; coordinateList.reserve(8); coordinateList.append( ring.at( NorthWest ) ); coordinateList.append( ring.at( SouthWest ) ); coordinateList.append( ring.at( SouthEast ) ); coordinateList.append( ring.at( NorthEast ) ); GeoDataCoordinates northernHandle = ring.at( NorthEast ).interpolate( ring.at( NorthWest ), 0.5 ); GeoDataCoordinates southernHandle = ring.at( SouthEast ).interpolate( ring.at( SouthWest ), 0.5 ); // Special case handle position to take tessellation // along latitude circles into account if (m_overlay->latLonBox().rotation() == 0) { northernHandle.setLatitude(ring.at( NorthEast ).latitude()); southernHandle.setLatitude(ring.at( SouthEast ).latitude()); } coordinateList.append( northernHandle ); coordinateList.append( southernHandle ); coordinateList.append( ring.at( NorthEast ).interpolate( ring.at( SouthEast ), 0.5 ) ); coordinateList.append( ring.at( NorthWest ).interpolate( ring.at( SouthWest ), 0.5 ) ); m_regionList.reserve(9); m_regionList.append( painter->regionFromEllipse( coordinateList.at( NorthWest ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( SouthWest ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( SouthEast ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( NorthEast ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( North ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( South ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( East ), 16, 16 ) ); m_regionList.append( painter->regionFromEllipse( coordinateList.at( West ), 16, 16 ) ); m_regionList.append( painter->regionFromPolygon( ring, Qt::OddEvenFill ) ); // Calculate handle icon orientation due to the projection qreal xNW, yNW, xSW, ySW; viewport->screenCoordinates(ring.at( NorthWest ), xNW, yNW); viewport->screenCoordinates(ring.at( SouthWest ), xSW, ySW); qreal westernAngle = qAtan2(ySW - yNW, xSW - xNW) - M_PI/2; qreal xNE, yNE, xSE, ySE; viewport->screenCoordinates(ring.at( NorthEast ), xNE, yNE); viewport->screenCoordinates(ring.at( SouthEast ), xSE, ySE); qreal easternAngle = qAtan2(ySE - yNE, xSE - xNE) - M_PI/2; painter->setPen( Qt::DashLine ); painter->setBrush( Qt::NoBrush ); painter->drawPolygon( ring ); qreal projectedAngle = 0; for( int i = NorthWest; i != Polygon; ++i ) { // Assign handle icon orientation due to the projection if (i == NorthWest || i == West || i == SouthWest) { projectedAngle = westernAngle; } else if (i == NorthEast || i == East || i == SouthEast) { projectedAngle = easternAngle; } else if (i == North || i == South) { projectedAngle = (westernAngle + easternAngle) / 2; } QTransform trans; trans.rotateRadians( projectedAngle ); if ( m_editStatus == Resize ){ if( m_hoveredHandle != i ) { painter->drawImage( coordinateList.at( i ), m_resizeIcons.at( 2*i ).transformed( trans, Qt::SmoothTransformation ) ); } else { painter->drawImage( coordinateList.at( i ), m_resizeIcons.at( 2*i + 1 ).transformed( trans, Qt::SmoothTransformation ) ); } } else if ( m_editStatus == Rotate ) { if( m_hoveredHandle != i ) { painter->drawImage( coordinateList.at( i ), m_rotateIcons.at( 2*i ).transformed( trans, Qt::SmoothTransformation ) ); } else { painter->drawImage( coordinateList.at( i ), m_rotateIcons.at( 2*i + 1 ).transformed( trans, Qt::SmoothTransformation ) ); } } } } painter->restore(); } bool GroundOverlayFrame::containsPoint( const QPoint &eventPos ) const { for ( const QRegion ®ion: m_regionList ) { if ( region.contains( eventPos ) ) { return true; } } // This is a bugfix to handle the events even if they occur outside of this object, // so when rotating or resizing the mouseReleaseEvent is handled successfully // TODO: maybe find a better way? if( m_movedHandle != NoRegion || m_hoveredHandle != NoRegion ) { return true; } return false; } void GroundOverlayFrame::dealWithItemChange( const SceneGraphicsItem *other ) { Q_UNUSED( other ); } void GroundOverlayFrame::move( const GeoDataCoordinates &source, const GeoDataCoordinates &destination ) { // not implemented yet Q_UNUSED( source ); Q_UNUSED( destination ); } bool GroundOverlayFrame::mousePressEvent( QMouseEvent *event ) { // React to all ellipse as well as to the polygon. for ( int i = 0; i < m_regionList.size(); ++i ) { if ( m_regionList.at(i).contains( event->pos() ) ) { m_movedHandle = i; qreal lon, lat; m_viewport->geoCoordinates( event->pos().x(), event->pos().y(), lon, lat, GeoDataCoordinates::Radian ); m_movedHandleGeoCoordinates.set( lon, lat ); m_movedHandleScreenCoordinates = event->pos(); m_previousRotation = m_overlay->latLonBox().rotation(); if ( m_movedHandle == Polygon ) { m_editStatusChangeNeeded = true; } return true; } } return false; } bool GroundOverlayFrame::mouseMoveEvent( QMouseEvent *event ) { if ( !m_viewport ) { return false; } // Catch hover events. if ( m_movedHandle == NoRegion ) { for ( int i = 0; i < m_regionList.size(); ++i ) { if ( m_regionList.at(i).contains( event->pos() ) ) { if ( i == Polygon ) { setRequest( ChangeCursorOverlayBodyHover ); } else { setRequest( ChangeCursorOverlayRotateHover ); } m_hoveredHandle = i; return true; } } m_hoveredHandle = NoRegion; return true; } else { m_editStatusChangeNeeded = false; } - if ( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { + if (geodata_cast(placemark()->geometry())) { qreal lon, lat; m_viewport->geoCoordinates( event->pos().x(), event->pos().y(), lon, lat, GeoDataCoordinates::Radian ); if ( m_editStatus == Resize ) { GeoDataCoordinates coord(lon, lat); GeoDataCoordinates rotatedCoord(coord); if (m_overlay->latLonBox().rotation() != 0) { rotatedCoord = coord.rotateAround(m_overlay->latLonBox().center(), -m_overlay->latLonBox().rotation()); } if ( m_movedHandle == NorthWest ) { m_overlay->latLonBox().setNorth( rotatedCoord.latitude() ); m_overlay->latLonBox().setWest( rotatedCoord.longitude() ); } else if ( m_movedHandle == SouthWest ) { m_overlay->latLonBox().setSouth( rotatedCoord.latitude() ); m_overlay->latLonBox().setWest( rotatedCoord.longitude() ); } else if ( m_movedHandle == SouthEast ) { m_overlay->latLonBox().setSouth( rotatedCoord.latitude() ); m_overlay->latLonBox().setEast( rotatedCoord.longitude() ); } else if ( m_movedHandle == NorthEast ) { m_overlay->latLonBox().setNorth( rotatedCoord.latitude() ); m_overlay->latLonBox().setEast( rotatedCoord.longitude() ); } else if ( m_movedHandle == North ) { m_overlay->latLonBox().setNorth( rotatedCoord.latitude() ); } else if ( m_movedHandle == South ) { m_overlay->latLonBox().setSouth( rotatedCoord.latitude() ); } else if ( m_movedHandle == East ) { m_overlay->latLonBox().setEast( rotatedCoord.longitude() ); } else if ( m_movedHandle == West ) { m_overlay->latLonBox().setWest( rotatedCoord.longitude() ); } } else if ( m_editStatus == Rotate ) { if ( m_movedHandle != Polygon ) { QPoint center = m_regionList.at( Polygon ).boundingRect().center(); qreal angle1 = qAtan2( event->pos().y() - center.y(), event->pos().x() - center.x() ); qreal angle2 = qAtan2( m_movedHandleScreenCoordinates.y() - center.y(), m_movedHandleScreenCoordinates.x() - center.x() ); m_overlay->latLonBox().setRotation( angle2 - angle1 + m_previousRotation ); } } if ( m_movedHandle == Polygon ) { const qreal centerLonDiff = lon - m_movedHandleGeoCoordinates.longitude(); const qreal centerLatDiff = lat - m_movedHandleGeoCoordinates.latitude(); m_overlay->latLonBox().setBoundaries( m_overlay->latLonBox().north() + centerLatDiff, m_overlay->latLonBox().south() + centerLatDiff, m_overlay->latLonBox().east() + centerLonDiff, m_overlay->latLonBox().west() + centerLonDiff ); m_movedHandleGeoCoordinates.set( lon, lat ); } update(); return true; } return false; } bool GroundOverlayFrame::mouseReleaseEvent( QMouseEvent *event ) { Q_UNUSED( event ); m_movedHandle = NoRegion; m_textureLayer->reset(); if( m_editStatusChangeNeeded ) { if( m_editStatus == Resize ) { m_editStatus = Rotate; } else { m_editStatus = Resize; } } return true; } void GroundOverlayFrame::update() { GeoDataLatLonBox overlayLatLonBox = m_overlay->latLonBox(); GeoDataPolygon *poly = dynamic_cast( placemark()->geometry() ); poly->outerBoundary().clear(); GeoDataCoordinates rotatedCoord; GeoDataCoordinates northWest(overlayLatLonBox.west(), overlayLatLonBox.north()); rotatedCoord = northWest.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation()); poly->outerBoundary().append( rotatedCoord ); GeoDataCoordinates southWest(overlayLatLonBox.west(), overlayLatLonBox.south()); rotatedCoord = southWest.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation()); poly->outerBoundary().append( rotatedCoord ); GeoDataCoordinates southEast(overlayLatLonBox.east(), overlayLatLonBox.south()); rotatedCoord = southEast.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation()); poly->outerBoundary().append( rotatedCoord ); GeoDataCoordinates northEast(overlayLatLonBox.east(), overlayLatLonBox.north()); rotatedCoord = northEast.rotateAround(overlayLatLonBox.center(), overlayLatLonBox.rotation()); poly->outerBoundary().append( rotatedCoord ); } void GroundOverlayFrame::dealWithStateChange( SceneGraphicsItem::ActionState previousState ) { Q_UNUSED( previousState ); } const char *GroundOverlayFrame::graphicType() const { return SceneGraphicsTypes::SceneGraphicGroundOverlay; } } diff --git a/src/plugins/render/annotate/NodeItemDelegate.cpp b/src/plugins/render/annotate/NodeItemDelegate.cpp index 327c0e5b0..547b4bac3 100644 --- a/src/plugins/render/annotate/NodeItemDelegate.cpp +++ b/src/plugins/render/annotate/NodeItemDelegate.cpp @@ -1,178 +1,168 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Stanciu Marius-Valeriu // // Self #include "NodeItemDelegate.h" // Qt #include #include // Marble #include "LatLonEdit.h" #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" #include "GeoDataLineString.h" #include "GeoDataLinearRing.h" #include "GeoDataPolygon.h" namespace Marble { QSize NodeItemDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const { Q_UNUSED( option ); Q_UNUSED( index ); return QSize( 25, 25 ); } NodeItemDelegate::NodeItemDelegate( GeoDataPlacemark* placemark, QTreeView* view ): m_placemark( placemark ), m_view( view ) { } QWidget* NodeItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const { Q_UNUSED( option ); Q_UNUSED( index ); LatLonEdit *editor = new LatLonEdit( parent ); connect( this, SIGNAL(closeEditor(QWidget*)), this, SLOT(unsetCurrentEditor(QWidget*)) ); return editor; } void NodeItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { LatLonEdit *latLonEditWidget = static_cast(editor); qreal value = 0; - if( m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { - - GeoDataPolygon *polygon = static_cast( m_placemark->geometry() ); - + if (const auto polygon = geodata_cast(m_placemark->geometry())) { GeoDataLinearRing outerBoundary = polygon->outerBoundary(); // Setting the latlonedit spinboxes values if( index.column() == 1 ) { latLonEditWidget->setDimension( Marble::Longitude ); value = outerBoundary.at( index.row() ).longitude( GeoDataCoordinates::Degree ); } else { latLonEditWidget->setDimension( Marble::Latitude ); value = outerBoundary.at( index.row() ).latitude( GeoDataCoordinates::Degree ); } } - else if ( m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { - - GeoDataLineString *lineString = static_cast( m_placemark->geometry() ); - + else if (const auto lineString = geodata_cast(m_placemark->geometry())) { // Setting the latlonedit spinboxes values if( index.column() == 1 ) { latLonEditWidget->setDimension( Marble::Longitude ); value = lineString->at( index.row() ).longitude( GeoDataCoordinates::Degree ); } else { latLonEditWidget->setDimension( Marble::Latitude ); value = lineString->at( index.row() ).latitude(GeoDataCoordinates::Degree ); } } latLonEditWidget->setValue( value ); connect( latLonEditWidget, SIGNAL(valueChanged(qreal)), this, SLOT(previewNodeMove(qreal)) ); m_indexBeingEdited = index; } void NodeItemDelegate::setModelData( QWidget* editor, QAbstractItemModel *model, const QModelIndex &index ) const { Q_UNUSED( editor ); Q_UNUSED( model ); Q_UNUSED( index ); // The dialogs already have a function that updates the NodeModel emit modelChanged( m_placemark ); } void NodeItemDelegate::previewNodeMove( qreal value ) { - if( m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { - GeoDataPolygon *polygon = static_cast( m_placemark->geometry() ); + if (const auto polygon = geodata_cast(m_placemark->geometry())) { GeoDataLinearRing outerBoundary = polygon->outerBoundary(); GeoDataCoordinates* coordinates = new GeoDataCoordinates( outerBoundary[m_indexBeingEdited.row()] ); if( m_indexBeingEdited.column() == 1) { coordinates->setLongitude( value, GeoDataCoordinates::Degree ); } else { coordinates->setLatitude( value, GeoDataCoordinates::Degree ); } outerBoundary[ m_indexBeingEdited.row() ] = *coordinates; polygon->setOuterBoundary( outerBoundary ); } - else if ( m_placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { - - GeoDataLineString *lineString = static_cast( m_placemark->geometry() ); + else if (const auto lineString = geodata_cast(m_placemark->geometry())) { GeoDataCoordinates* coordinates = new GeoDataCoordinates( lineString->at( m_indexBeingEdited.row() ) ); if( m_indexBeingEdited.column() == 1) { coordinates->setLongitude( value, GeoDataCoordinates::Degree ); } else { coordinates->setLatitude( value, GeoDataCoordinates::Degree ); } lineString->at( m_indexBeingEdited.row() ) = *coordinates; } // Updating chagnes ( repainting graphics ) emit geometryChanged(); } void NodeItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { if( index.column() == 1) { m_view->setColumnWidth( 1, 200 ); m_view->setColumnWidth( 2, 100 ); } else { m_view->setColumnWidth( 2, 200 ); m_view->setColumnWidth( 1, 100 ); } editor->setGeometry( option.rect ); } void NodeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { drawBackground( painter, option, index ); // The LatLonEdit widget is transparent, so we have to disable the text behind it // for esthetic reasons. if ( !( index == m_indexBeingEdited ) || !( index == m_view->currentIndex() ) ) { drawDisplay( painter, option, option.rect, index.data().toString() ); } } void NodeItemDelegate::unsetCurrentEditor(QWidget* widget) { Q_UNUSED( widget ); m_indexBeingEdited = QModelIndex(); m_view->viewport()->update(); } } #include "moc_NodeItemDelegate.cpp" diff --git a/src/plugins/render/annotate/PolylineAnnotation.cpp b/src/plugins/render/annotate/PolylineAnnotation.cpp index 69954e1ca..1d916f496 100644 --- a/src/plugins/render/annotate/PolylineAnnotation.cpp +++ b/src/plugins/render/annotate/PolylineAnnotation.cpp @@ -1,843 +1,842 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Calin Cruceru // // Self #include "PolylineAnnotation.h" // Qt #include #include #include // Marble #include "SceneGraphicsTypes.h" #include "GeoPainter.h" #include "PolylineNode.h" #include "MarbleMath.h" #include "GeoDataLineString.h" #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" #include "ViewportParams.h" #include "MergingPolylineNodesAnimation.h" #include "osm/OsmPlacemarkData.h" namespace Marble { const int PolylineAnnotation::regularDim = 15; const int PolylineAnnotation::selectedDim = 15; const int PolylineAnnotation::mergedDim = 20; const int PolylineAnnotation::hoveredDim = 20; const QColor PolylineAnnotation::regularColor = Oxygen::aluminumGray3; const QColor PolylineAnnotation::mergedColor = Oxygen::emeraldGreen6; PolylineAnnotation::PolylineAnnotation( GeoDataPlacemark *placemark ) : SceneGraphicsItem( placemark ), m_viewport( 0 ), m_regionsInitialized( false ), m_busy( false ), m_interactingObj( InteractingNothing ), m_clickedNodeIndex( -1 ), m_hoveredNodeIndex( -1 ), m_virtualHoveredNode( -1 ) { setPaintLayers(QStringList() << "PolylineAnnotation"); } PolylineAnnotation::~PolylineAnnotation() { delete m_animation; } void PolylineAnnotation::paint(GeoPainter *painter, const ViewportParams *viewport , const QString &layer, int tileZoomLevel) { Q_UNUSED(layer); Q_UNUSED(tileZoomLevel); m_viewport = viewport; - Q_ASSERT( placemark()->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ); + Q_ASSERT(geodata_cast(placemark()->geometry())); painter->save(); if ( state() == SceneGraphicsItem::DrawingPolyline || !m_regionsInitialized ) { setupRegionsLists( painter ); m_regionsInitialized = true; } else { updateRegions( painter ); } if ( hasFocus() ) { drawNodes( painter ); } painter->restore(); } void PolylineAnnotation::setupRegionsLists( GeoPainter *painter ) { Q_ASSERT( state() == SceneGraphicsItem::DrawingPolyline || !m_regionsInitialized ); const GeoDataLineString line = static_cast( *placemark()->geometry() ); // Add poyline nodes. QVector::ConstIterator itBegin = line.constBegin(); QVector::ConstIterator itEnd = line.constEnd(); m_nodesList.clear(); m_nodesList.reserve(line.size()); for ( ; itBegin != itEnd; ++itBegin ) { const PolylineNode newNode = PolylineNode( painter->regionFromEllipse( *itBegin, regularDim, regularDim ) ); m_nodesList.append( newNode ); } // Add region from polyline so that events on polyline's 'lines' could be caught. m_polylineRegion = painter->regionFromPolyline( line, 15 ); } void PolylineAnnotation::updateRegions( GeoPainter *painter ) { if ( m_busy ) { return; } const GeoDataLineString line = static_cast( *placemark()->geometry() ); if ( state() == SceneGraphicsItem::AddingNodes ) { // Create and update virtual nodes lists when being in the AddingPolgonNodes state, to // avoid overhead in other states. m_virtualNodesList.clear(); for ( int i = 0; i < line.size() - 1; ++i ) { const QRegion newRegion( painter->regionFromEllipse( line.at(i).interpolate( line.at(i+1), 0.5 ), hoveredDim, hoveredDim ) ); m_virtualNodesList.append( PolylineNode( newRegion ) ); } } // Update the polyline region; m_polylineRegion = painter->regionFromPolyline( line, 15 ); // Update the node lists. for ( int i = 0; i < m_nodesList.size(); ++i ) { const QRegion newRegion = m_nodesList.at(i).isSelected() ? painter->regionFromEllipse( line.at(i), selectedDim, selectedDim ) : painter->regionFromEllipse( line.at(i), regularDim, regularDim ); m_nodesList[i].setRegion( newRegion ); } } void PolylineAnnotation::drawNodes( GeoPainter *painter ) { // These are the 'real' dimensions of the drawn nodes. The ones which have class scope are used // to generate the regions and they are a little bit larger, because, for example, it would be // a little bit too hard to select nodes. static const int d_regularDim = 10; static const int d_selectedDim = 10; static const int d_mergedDim = 20; static const int d_hoveredDim = 20; const GeoDataLineString line = static_cast( *placemark()->geometry() ); QColor glowColor = QApplication::palette().highlightedText().color(); glowColor.setAlpha(120); auto const selectedColor = QApplication::palette().highlight().color(); auto const hoveredColor = selectedColor; for ( int i = 0; i < line.size(); ++i ) { // The order here is important, because a merged node can be at the same time selected. if ( m_nodesList.at(i).isBeingMerged() ) { painter->setBrush( mergedColor ); painter->drawEllipse( line.at(i), d_mergedDim, d_mergedDim ); } else if ( m_nodesList.at(i).isSelected() ) { painter->setBrush( selectedColor ); painter->drawEllipse( line.at(i), d_selectedDim, d_selectedDim ); if ( m_nodesList.at(i).isEditingHighlighted() || m_nodesList.at(i).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setBrush( Qt::NoBrush ); painter->setPen( newPen ); painter->drawEllipse( line.at(i), d_selectedDim + 2, d_selectedDim + 2 ); painter->setPen( defaultPen ); } } else { painter->setBrush( regularColor ); painter->drawEllipse( line.at(i), d_regularDim, d_regularDim ); if ( m_nodesList.at(i).isEditingHighlighted() || m_nodesList.at(i).isMergingHighlighted() ) { QPen defaultPen = painter->pen(); QPen newPen; newPen.setWidth( defaultPen.width() + 3 ); newPen.setColor( glowColor ); painter->setPen( newPen ); painter->setBrush( Qt::NoBrush ); painter->drawEllipse( line.at(i), d_regularDim + 2, d_regularDim + 2 ); painter->setPen( defaultPen ); } } } if ( m_virtualHoveredNode != -1 ) { painter->setBrush( hoveredColor ); GeoDataCoordinates newCoords; if ( m_virtualHoveredNode + 1 ) { newCoords = line.at( m_virtualHoveredNode + 1 ).interpolate( line.at( m_virtualHoveredNode ), 0.5 ); } else { newCoords = line.first().interpolate( line.last(), 0.5 ); } painter->drawEllipse( newCoords, d_hoveredDim, d_hoveredDim ); } } bool PolylineAnnotation::containsPoint( const QPoint &point ) const { if ( state() == SceneGraphicsItem::Editing ) { return nodeContains( point ) != -1 || polylineContains( point ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { return nodeContains( point ) != -1; } else if ( state() == SceneGraphicsItem::AddingNodes ) { return virtualNodeContains( point ) != -1 || nodeContains( point ) != -1 || polylineContains( point ); } return false; } int PolylineAnnotation::nodeContains( const QPoint &point ) const { if ( !hasFocus() ) { return -1; } for ( int i = 0; i < m_nodesList.size(); ++i ) { if ( m_nodesList.at(i).containsPoint( point ) ) { return i; } } return -1; } int PolylineAnnotation::virtualNodeContains( const QPoint &point ) const { if ( !hasFocus() ) { return -1; } for ( int i = 0; i < m_virtualNodesList.size(); ++i ) { if ( m_virtualNodesList.at(i).containsPoint( point ) ) return i; } return -1; } bool PolylineAnnotation::polylineContains( const QPoint &point ) const { return m_polylineRegion.contains( point ); } void PolylineAnnotation::dealWithItemChange( const SceneGraphicsItem *other ) { Q_UNUSED( other ); // So far we only deal with item changes when hovering nodes, so that // they do not remain hovered when changing the item we interact with. if ( state() == SceneGraphicsItem::Editing ) { if ( m_hoveredNodeIndex != -1 && m_hoveredNodeIndex < static_cast( placemark()->geometry() )->size() ) { m_nodesList[m_hoveredNodeIndex].setFlag( PolylineNode::NodeIsEditingHighlighted, false ); } m_hoveredNodeIndex = -1; } else if ( state() == SceneGraphicsItem::MergingNodes ) { if ( m_hoveredNodeIndex != -1 ) { m_nodesList[m_hoveredNodeIndex].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); } m_hoveredNodeIndex = -1; } else if ( state() == SceneGraphicsItem::AddingNodes ) { m_virtualHoveredNode = -1; } } void PolylineAnnotation::move( const GeoDataCoordinates &source, const GeoDataCoordinates &destination ) { GeoDataLineString *lineString = static_cast( placemark()->geometry() ); GeoDataLineString oldLineString = *lineString; OsmPlacemarkData *osmData = 0; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); } lineString->clear(); const qreal deltaLat = destination.latitude() - source.latitude(); const qreal deltaLon = destination.longitude() - source.longitude(); Quaternion latRectAxis = Quaternion::fromEuler( 0, destination.longitude(), 0); Quaternion latAxis = Quaternion::fromEuler( -deltaLat, 0, 0); Quaternion lonAxis = Quaternion::fromEuler(0, deltaLon, 0); Quaternion rotAxis = latRectAxis * latAxis * latRectAxis.inverse() * lonAxis; qreal lonRotated, latRotated; for ( int i = 0; i < oldLineString.size(); ++i ) { Quaternion qpos = oldLineString.at(i).quaternion(); qpos.rotateAroundAxis(rotAxis); qpos.getSpherical( lonRotated, latRotated ); GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 ); if ( osmData ) { osmData->changeNodeReference( oldLineString.at( i ), movedPoint ); } lineString->append( movedPoint ); } } void PolylineAnnotation::setBusy( bool enabled ) { m_busy = enabled; if ( !enabled && m_animation && state() == SceneGraphicsItem::MergingNodes ) { if ( m_firstMergedNode != -1 && m_secondMergedNode != -1 ) { // Update the PolylineNodes lists after the animation has finished its execution. m_nodesList[m_secondMergedNode].setFlag( PolylineNode::NodeIsMergingHighlighted, false ); m_hoveredNodeIndex = -1; // Remove the merging node flag and add the NodeIsSelected flag if either one of the // merged nodes had been selected before merging them. m_nodesList[m_secondMergedNode].setFlag( PolylineNode::NodeIsMerged, false ); if ( m_nodesList[m_firstMergedNode].isSelected() ) { m_nodesList[m_secondMergedNode].setFlag( PolylineNode::NodeIsSelected ); } m_nodesList.removeAt( m_firstMergedNode ); m_firstMergedNode = -1; m_secondMergedNode = -1; } delete m_animation; } } bool PolylineAnnotation::isBusy() const { return m_busy; } void PolylineAnnotation::deselectAllNodes() { if ( state() != SceneGraphicsItem::Editing ) { return; } for ( int i = 0 ; i < m_nodesList.size(); ++i ) { m_nodesList[i].setFlag( PolylineNode::NodeIsSelected, false ); } } void PolylineAnnotation::deleteAllSelectedNodes() { if ( state() != SceneGraphicsItem::Editing ) { return; } GeoDataLineString *line = static_cast( placemark()->geometry() ); OsmPlacemarkData *osmData = 0; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); } for ( int i = 0; i < line->size(); ++i ) { if ( m_nodesList.at(i).isSelected() ) { if ( m_nodesList.size() <= 2 ) { setRequest( SceneGraphicsItem::RemovePolylineRequest ); return; } if ( osmData ) { osmData->removeNodeReference( line->at( i ) ); } m_nodesList.removeAt( i ); line->remove( i ); --i; } } } void PolylineAnnotation::deleteClickedNode() { if ( state() != SceneGraphicsItem::Editing ) { return; } GeoDataLineString *line = static_cast( placemark()->geometry() ); OsmPlacemarkData *osmData = 0; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); } if ( m_nodesList.size() <= 2 ) { setRequest( SceneGraphicsItem::RemovePolylineRequest ); return; } if ( osmData ) { osmData->removeMemberReference( m_clickedNodeIndex ); } m_nodesList.removeAt( m_clickedNodeIndex ); line->remove( m_clickedNodeIndex ); } void PolylineAnnotation::changeClickedNodeSelection() { if ( state() != SceneGraphicsItem::Editing ) { return; } m_nodesList[m_clickedNodeIndex].setFlag( PolylineNode::NodeIsSelected, !m_nodesList[m_clickedNodeIndex].isSelected() ); } bool PolylineAnnotation::hasNodesSelected() const { for ( int i = 0; i < m_nodesList.size(); ++i ) { if ( m_nodesList.at(i).isSelected() ) { return true; } } return false; } bool PolylineAnnotation::clickedNodeIsSelected() const { return m_nodesList[m_clickedNodeIndex].isSelected(); } QPointer PolylineAnnotation::animation() { return m_animation; } bool PolylineAnnotation::mousePressEvent( QMouseEvent *event ) { if ( !m_viewport || m_busy ) { return false; } setRequest( SceneGraphicsItem::NoRequest ); if ( state() == SceneGraphicsItem::Editing ) { return processEditingOnPress( event ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { return processMergingOnPress( event ); } else if ( state() == SceneGraphicsItem::AddingNodes ) { return processAddingNodesOnPress( event ); } return false; } bool PolylineAnnotation::mouseMoveEvent( QMouseEvent *event ) { if ( !m_viewport || m_busy ) { return false; } setRequest( SceneGraphicsItem::NoRequest ); if ( state() == SceneGraphicsItem::Editing ) { return processEditingOnMove( event ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { return processMergingOnMove( event ); } else if ( state() == SceneGraphicsItem::AddingNodes ) { return processAddingNodesOnMove( event ); } return false; } bool PolylineAnnotation::mouseReleaseEvent( QMouseEvent *event ) { if ( !m_viewport || m_busy ) { return false; } setRequest( SceneGraphicsItem::NoRequest ); if ( state() == SceneGraphicsItem::Editing ) { return processEditingOnRelease( event ); } else if ( state() == SceneGraphicsItem::MergingNodes ) { return processMergingOnRelease( event ); } else if ( state() == SceneGraphicsItem::AddingNodes ) { return processAddingNodesOnRelease( event ); } return false; } void PolylineAnnotation::dealWithStateChange( SceneGraphicsItem::ActionState previousState ) { // Dealing with cases when exiting a state has an effect on this item. if ( previousState == SceneGraphicsItem::DrawingPolyline ) { // nothing so far } else if ( previousState == SceneGraphicsItem::Editing ) { // Make sure that when changing the state, there is no highlighted node. if ( m_hoveredNodeIndex != -1 ) { m_nodesList[m_hoveredNodeIndex].setFlag( PolylineNode::NodeIsEditingHighlighted, false ); } m_clickedNodeIndex = -1; m_hoveredNodeIndex = -1; } else if ( previousState == SceneGraphicsItem::MergingNodes ) { // If there was only a node selected for being merged and the state changed, // deselect it. if ( m_firstMergedNode != -1 ) { m_nodesList[m_firstMergedNode].setFlag( PolylineNode::NodeIsMerged, false ); } // Make sure that when changing the state, there is no highlighted node. if ( m_hoveredNodeIndex != -1 ) { if ( m_hoveredNodeIndex != -1 ) { m_nodesList[m_hoveredNodeIndex].setFlag( PolylineNode::NodeIsEditingHighlighted, false ); } } m_hoveredNodeIndex = -1; delete m_animation; } else if ( previousState == SceneGraphicsItem::AddingNodes ) { m_virtualNodesList.clear(); m_virtualHoveredNode = -1; m_adjustedNode = -1; } // Dealing with cases when entering a state has an effect on this item, or // initializations are needed. if ( state() == SceneGraphicsItem::Editing ) { m_interactingObj = InteractingNothing; m_clickedNodeIndex = -1; m_hoveredNodeIndex = -1; } else if ( state() == SceneGraphicsItem::MergingNodes ) { m_firstMergedNode = -1; m_secondMergedNode = -1; m_hoveredNodeIndex = -1; m_animation = 0; } else if ( state() == SceneGraphicsItem::AddingNodes ) { m_virtualHoveredNode = -1; m_adjustedNode = -1; } } bool PolylineAnnotation::processEditingOnPress( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != Qt::LeftButton && mouseEvent->button() != Qt::RightButton ) { return false; } qreal lat, lon; m_viewport->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); m_movedPointCoords.set( lon, lat ); // First check if one of the nodes has been clicked. m_clickedNodeIndex = nodeContains( mouseEvent->pos() ); if ( m_clickedNodeIndex != -1 ) { if ( mouseEvent->button() == Qt::RightButton ) { setRequest( SceneGraphicsItem::ShowNodeRmbMenu ); } else { Q_ASSERT( mouseEvent->button() == Qt::LeftButton ); m_interactingObj = InteractingNode; } return true; } // Then check if the 'interior' of the polyline has been clicked (by interior // I mean its lines excepting its nodes). if ( polylineContains( mouseEvent->pos() ) ) { if ( mouseEvent->button() == Qt::RightButton ) { setRequest( SceneGraphicsItem::ShowPolylineRmbMenu ); } else { Q_ASSERT( mouseEvent->button() == Qt::LeftButton ); m_interactingObj = InteractingPolyline; } return true; } return false; } bool PolylineAnnotation::processEditingOnMove( QMouseEvent *mouseEvent ) { if ( !m_viewport ) { return false; } qreal lon, lat; m_viewport->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); const GeoDataCoordinates newCoords( lon, lat ); if ( m_interactingObj == InteractingNode ) { GeoDataLineString *line = static_cast( placemark()->geometry() ); OsmPlacemarkData *osmData = 0; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); } // Keeping the OsmPlacemarkData synchronized with the geometry if ( osmData ) { osmData->changeNodeReference( line->at( m_clickedNodeIndex ), newCoords ); } line->at(m_clickedNodeIndex) = newCoords; return true; } else if ( m_interactingObj == InteractingPolyline ) { GeoDataLineString *lineString = static_cast( placemark()->geometry() ); OsmPlacemarkData *osmData = 0; if ( placemark()->hasOsmData() ) { osmData = &placemark()->osmData(); } const GeoDataLineString oldLineString = *lineString; lineString->clear(); const qreal deltaLat = lat - m_movedPointCoords.latitude(); const qreal deltaLon = lon - m_movedPointCoords.longitude(); Quaternion latRectAxis = Quaternion::fromEuler( 0, lon, 0); Quaternion latAxis = Quaternion::fromEuler( -deltaLat, 0, 0); Quaternion lonAxis = Quaternion::fromEuler(0, deltaLon, 0); Quaternion rotAxis = latRectAxis * latAxis * latRectAxis.inverse() * lonAxis; qreal lonRotated, latRotated; for ( int i = 0; i < oldLineString.size(); ++i ) { Quaternion qpos = oldLineString.at(i).quaternion(); qpos.rotateAroundAxis(rotAxis); qpos.getSpherical( lonRotated, latRotated ); GeoDataCoordinates movedPoint( lonRotated, latRotated, 0 ); if ( osmData ) { osmData->changeNodeReference( oldLineString.at( i ), movedPoint ); } lineString->append( movedPoint ); } m_movedPointCoords = newCoords; return true; } return dealWithHovering( mouseEvent ); } bool PolylineAnnotation::processEditingOnRelease( QMouseEvent *mouseEvent ) { static const int mouseMoveOffset = 1; if ( mouseEvent->button() != Qt::LeftButton ) { return false; } if ( m_interactingObj == InteractingNode ) { qreal x, y; m_viewport->screenCoordinates( m_movedPointCoords.longitude(), m_movedPointCoords.latitude(), x, y ); // The node gets selected only if it is clicked and not moved. if ( qFabs(mouseEvent->pos().x() - x) > mouseMoveOffset || qFabs(mouseEvent->pos().y() - y) > mouseMoveOffset ) { m_interactingObj = InteractingNothing; return true; } m_nodesList[m_clickedNodeIndex].setFlag( PolylineNode::NodeIsSelected, !m_nodesList.at(m_clickedNodeIndex).isSelected() ); m_interactingObj = InteractingNothing; return true; } else if ( m_interactingObj == InteractingPolyline ) { // Nothing special happens at polyline release. m_interactingObj = InteractingNothing; return true; } return false; } bool PolylineAnnotation::processMergingOnPress( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != Qt::LeftButton ) { return false; } GeoDataLineString line = static_cast( *placemark()->geometry() ); const int index = nodeContains( mouseEvent->pos() ); if ( index == -1 ) { return false; } // If this is the first node selected to be merged. if ( m_firstMergedNode == -1 ) { m_firstMergedNode = index; m_nodesList[index].setFlag( PolylineNode::NodeIsMerged ); } else { Q_ASSERT( m_firstMergedNode != -1 ); // Clicking two times the same node results in unmarking it for merging. if ( m_firstMergedNode == index ) { m_nodesList[index].setFlag( PolylineNode::NodeIsMerged, false ); m_firstMergedNode = -1; return true; } // If these two nodes are the last ones remained as part of the polyline, remove // the whole polyline. if ( line.size() <= 2 ) { setRequest( SceneGraphicsItem::RemovePolylineRequest ); return true; } m_nodesList[index].setFlag( PolylineNode::NodeIsMerged ); m_secondMergedNode = index; delete m_animation; m_animation = new MergingPolylineNodesAnimation( this ); setRequest( SceneGraphicsItem::StartPolylineAnimation ); } return true; } bool PolylineAnnotation::processMergingOnMove( QMouseEvent *mouseEvent ) { return dealWithHovering( mouseEvent ); } bool PolylineAnnotation::processMergingOnRelease( QMouseEvent *mouseEvent ) { Q_UNUSED( mouseEvent ); return true; } bool PolylineAnnotation::processAddingNodesOnPress( QMouseEvent *mouseEvent ) { if ( mouseEvent->button() != Qt::LeftButton ) { return false; } GeoDataLineString *line = static_cast( placemark()->geometry() ); // If a virtual node has just been clicked, add it to the polyline and start 'adjusting' // its position. const int virtualIndex = virtualNodeContains( mouseEvent->pos() ); if ( virtualIndex != -1 && m_adjustedNode == -1 ) { Q_ASSERT( m_virtualHoveredNode == virtualIndex ); line->insert( virtualIndex + 1, line->at( virtualIndex ).interpolate( line->at( virtualIndex + 1 ), 0.5 ) ); m_nodesList.insert( virtualIndex + 1, PolylineNode() ); m_adjustedNode = virtualIndex + 1; m_virtualHoveredNode = -1; return true; } // If a virtual node which has been previously clicked and selected to become a // 'real node' is clicked one more time, it stops from being 'adjusted'. const int realIndex = nodeContains( mouseEvent->pos() ); if ( realIndex != -1 && m_adjustedNode != -1 ) { m_adjustedNode = -1; return true; } return false; } bool PolylineAnnotation::processAddingNodesOnMove( QMouseEvent *mouseEvent ) { Q_ASSERT( mouseEvent->button() == Qt::NoButton ); const int index = virtualNodeContains( mouseEvent->pos() ); // If we are adjusting a virtual node which has just been clicked and became real, just // change its coordinates when moving it, as we do with nodes in Editing state on move. if ( m_adjustedNode != -1 ) { // The virtual node which has just been added is always the last within // GeoDataLinearRing's container.qreal lon, lat; qreal lon, lat; m_viewport->geoCoordinates( mouseEvent->pos().x(), mouseEvent->pos().y(), lon, lat, GeoDataCoordinates::Radian ); const GeoDataCoordinates newCoords( lon, lat ); GeoDataLineString *line = static_cast( placemark()->geometry() ); line->at(m_adjustedNode) = newCoords; return true; // If we are hovering a virtual node, store its index in order to be painted in drawNodes // method. } else if ( index != -1 ) { m_virtualHoveredNode = index; return true; } return false; } bool PolylineAnnotation::processAddingNodesOnRelease( QMouseEvent *mouseEvent ) { Q_UNUSED( mouseEvent ); return m_adjustedNode == -1; } bool PolylineAnnotation::dealWithHovering( QMouseEvent *mouseEvent ) { const PolylineNode::PolyNodeFlag flag = state() == SceneGraphicsItem::Editing ? PolylineNode::NodeIsEditingHighlighted : PolylineNode::NodeIsMergingHighlighted; const int index = nodeContains( mouseEvent->pos() ); if ( index != -1 ) { if ( !m_nodesList.at(index).isEditingHighlighted() && !m_nodesList.at(index).isMergingHighlighted() ) { // Deal with the case when two nodes are very close to each other. if ( m_hoveredNodeIndex != -1 ) { m_nodesList[m_hoveredNodeIndex].setFlag( flag, false ); } m_hoveredNodeIndex = index; m_nodesList[index].setFlag( flag ); setRequest( ChangeCursorPolylineNodeHover ); } return true; } else if ( m_hoveredNodeIndex != -1 ) { m_nodesList[m_hoveredNodeIndex].setFlag( flag, false ); m_hoveredNodeIndex = -1; return true; } // This means that the interior of the polyline has been hovered so we catch this event too. setRequest( ChangeCursorPolylineLineHover ); return true; } const char *PolylineAnnotation::graphicType() const { return SceneGraphicsTypes::SceneGraphicPolylineAnnotation; } } diff --git a/src/plugins/runner/osm/translators/O5mWriter.cpp b/src/plugins/runner/osm/translators/O5mWriter.cpp index 3f28bdf6a..45a66be34 100644 --- a/src/plugins/runner/osm/translators/O5mWriter.cpp +++ b/src/plugins/runner/osm/translators/O5mWriter.cpp @@ -1,344 +1,341 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Dennis Nienhüser // #include "O5mWriter.h" -#include "GeoDataTypes.h" #include "GeoDataDocument.h" #include "GeoDataLineString.h" #include "GeoDataLinearRing.h" #include "GeoDataPlacemark.h" #include "GeoDataRelation.h" #include "GeoDataPolygon.h" #include "GeoWriter.h" #include "osm/OsmPlacemarkData.h" #include #include namespace Marble { QSet O5mWriter::m_blacklistedTags; bool O5mWriter::write(QIODevice *device, const GeoDataDocument &document) { if (!device || !device->isWritable()) { return false; } OsmConverter converter; converter.read(&document); QDataStream stream(device); writeHeader(stream); writeNodes(converter.nodes(), stream); writeWays(converter.ways(), stream); writeRelations(converter.relations(), stream); writeTrailer(stream); return true; } void O5mWriter::writeHeader(QDataStream &stream) const { stream << qint8(0xff); // o5m file start indicator stream << qint8(0xe0); // o5m header block indicator stream << qint8(0x04) << qint8(0x6f) << qint8(0x35) << qint8(0x6d) << qint8(0x32); // o5m header } void O5mWriter::writeNodes(const OsmConverter::Nodes &nodes, QDataStream &stream) const { if (nodes.empty()) { return; } stream << qint8(0xff); // reset delta encoding counters StringTable stringTable; qint64 lastId = 0; double lastLon = 0.0; double lastLat = 0.0; for(auto const & node: nodes) { if (node.second.id() == lastId) { continue; } stream << qint8(0x10); // node section start indicator QBuffer buffer; buffer.open(QIODevice::WriteOnly); QDataStream bufferStream(&buffer); OsmPlacemarkData const & osmData = node.second; qint64 idDiff = osmData.id() - lastId; writeSigned(idDiff, bufferStream); writeVersion(osmData, bufferStream); GeoDataCoordinates const & coordinates = node.first; double const lon = coordinates.longitude(GeoDataCoordinates::Degree); double const lat = coordinates.latitude(GeoDataCoordinates::Degree); writeSigned(deltaTo(lon, lastLon), bufferStream); writeSigned(deltaTo(lat, lastLat), bufferStream); writeTags(osmData, stringTable, bufferStream); writeUnsigned(buffer.size(), stream); stream.writeRawData(buffer.data().constData(), buffer.size()); lastId = osmData.id(); lastLon = lon; lastLat = lat; } } void O5mWriter::writeWays(const OsmConverter::Ways &ways, QDataStream &stream) const { if (ways.empty()) { return; } stream << qint8(0xff); // reset delta encoding counters StringTable stringTable; qint64 lastId = 0; qint64 lastReferenceId = 0; for (auto const & way: ways) { Q_ASSERT(way.first); if (way.second.id() == lastId) { continue; } stream << qint8(0x11); // way start indicator OsmPlacemarkData const & osmData = way.second; QBuffer buffer; buffer.open(QIODevice::WriteOnly); QDataStream bufferStream(&buffer); qint64 idDiff = osmData.id() - lastId; writeSigned(idDiff, bufferStream); lastId = osmData.id(); writeVersion(osmData, bufferStream); QBuffer referencesBuffer; referencesBuffer.open(QIODevice::WriteOnly); QDataStream referencesStream(&referencesBuffer); writeReferences(*way.first, lastReferenceId, osmData, referencesStream); writeUnsigned(referencesBuffer.size(), bufferStream); bufferStream.writeRawData(referencesBuffer.data().constData(), referencesBuffer.size()); writeTags(osmData, stringTable, bufferStream); writeUnsigned(buffer.size(), stream); stream.writeRawData(buffer.data().constData(), buffer.size()); } } void O5mWriter::writeRelations(const OsmConverter::Relations &relations, QDataStream &stream) const { if (relations.empty()) { return; } stream << qint8(0xff); // reset delta encoding counters StringTable stringTable; qint64 lastId = 0; qint64 lastReferenceId = 0; for (auto const & relation: relations) { if (relation.second.id() == lastId) { continue; } stream << qint8(0x12); // relation start indicator OsmPlacemarkData const & osmData = relation.second; QBuffer buffer; buffer.open(QIODevice::WriteOnly); QDataStream bufferStream(&buffer); qint64 idDiff = osmData.id() - lastId; writeSigned(idDiff, bufferStream); lastId = osmData.id(); writeVersion(osmData, bufferStream); QBuffer referencesBuffer; referencesBuffer.open(QIODevice::WriteOnly); QDataStream referencesStream(&referencesBuffer); - if (relation.first->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - auto placemark = static_cast(relation.first); - Q_ASSERT(placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType); - auto polygon = static_cast(placemark->geometry()); + if (const auto placemark = geodata_cast(relation.first)) { + auto polygon = geodata_cast(placemark->geometry()); + Q_ASSERT(polygon); writeMultipolygonMembers(*polygon, lastReferenceId, osmData, stringTable, referencesStream); - } else if (relation.first->nodeType() == GeoDataTypes::GeoDataRelationType) { - auto placemark = static_cast(relation.first); + } else if (const auto placemark = geodata_cast(relation.first)) { writeRelationMembers(placemark, lastReferenceId, osmData, stringTable, referencesStream); } else { Q_ASSERT(false); } writeUnsigned(referencesBuffer.size(), bufferStream); bufferStream.writeRawData(referencesBuffer.data().constData(), referencesBuffer.size()); writeTags(osmData, stringTable, bufferStream); writeUnsigned(buffer.size(), stream); stream.writeRawData(buffer.data().constData(), buffer.size()); } } void O5mWriter::writeTrailer(QDataStream &stream) const { stream << qint8(0xfe); // o5m file end indicator } void O5mWriter::writeMultipolygonMembers(const GeoDataPolygon &polygon, qint64 &lastId, const OsmPlacemarkData &osmData, StringTable &stringTable, QDataStream &stream) const { qint64 id = osmData.memberReference(-1).id(); qint64 idDiff = id - lastId; writeSigned(idDiff, stream); lastId = id; writeStringPair(StringPair("1outer", QString()), stringTable, stream); // type=way, role=outer for (int index = 0; index < polygon.innerBoundaries().size(); ++index) { id = osmData.memberReference( index ).id(); qint64 idDiff = id - lastId; writeSigned(idDiff, stream); writeStringPair(StringPair("1inner", QString()), stringTable, stream); // type=way, role=inner lastId = id; } } void O5mWriter::writeRelationMembers(const GeoDataRelation *relation, qint64 &lastId, const OsmPlacemarkData &osmData, O5mWriter::StringTable &stringTable, QDataStream &stream) const { Q_UNUSED(relation); for (auto iter = osmData.relationReferencesBegin(), end = osmData.relationReferencesEnd(); iter != end; ++iter) { qint64 id = iter.key(); qint64 idDiff = id - lastId; writeSigned(idDiff, stream); auto const key = QString("1%1").arg(iter.value()); writeStringPair(StringPair(key, QString()), stringTable, stream); // type=way, role=... lastId = id; } } void O5mWriter::writeReferences(const GeoDataLineString &lineString, qint64 &lastId, const OsmPlacemarkData &osmData, QDataStream &stream) const { QVector::const_iterator it = lineString.constBegin(); QVector::ConstIterator const end = lineString.constEnd(); for ( ; it != end; ++it ) { qint64 id = osmData.nodeReference( *it ).id(); qint64 idDiff = id - lastId; writeSigned(idDiff, stream); lastId = id; } if (!lineString.isEmpty() && lineString.isClosed()) { auto const startId = osmData.nodeReference(lineString.first()).id(); auto const endId = osmData.nodeReference(lineString.last()).id(); if (startId != endId) { qint64 idDiff = startId - lastId; writeSigned(idDiff, stream); lastId = startId; } } } void O5mWriter::writeVersion(const OsmPlacemarkData &, QDataStream &stream) const { stream << qint8(0x00); // no version information /** @todo implement */ } void O5mWriter::writeTags(const OsmPlacemarkData &osmData, StringTable &stringTable, QDataStream &stream) const { if (m_blacklistedTags.isEmpty()) { m_blacklistedTags << QStringLiteral("mx:version"); m_blacklistedTags << QStringLiteral("mx:changeset"); m_blacklistedTags << QStringLiteral("mx:uid"); m_blacklistedTags << QStringLiteral("mx:visible"); m_blacklistedTags << QStringLiteral("mx:user"); m_blacklistedTags << QStringLiteral("mx:timestamp"); m_blacklistedTags << QStringLiteral("mx:action"); } for (auto iter=osmData.tagsBegin(), end = osmData.tagsEnd(); iter != end; ++iter) { if (!m_blacklistedTags.contains(iter.key())) { writeStringPair(StringPair(iter.key(), iter.value()), stringTable, stream); } } } void O5mWriter::writeStringPair(const StringPair &pair, StringTable &stringTable, QDataStream &stream) const { Q_ASSERT(stringTable.size() <= 15000); auto const iter = stringTable.constFind(pair); if (iter == stringTable.cend()) { QByteArray data; data.push_back(char(0x00)); data.push_back(pair.first.toUtf8()); if (!pair.second.isEmpty()) { data.push_back(char(0x00)); data.push_back(pair.second.toUtf8()); } data.push_back(char(0x00)); stream.writeRawData(data.constData(), data.size()); bool const tooLong = pair.first.size() + pair.second.size() > 250; bool const tableFull = stringTable.size() > 15000; if (!tooLong && !tableFull) { /* When the table is full, old values could be re-used. * See o5m spec. This is only relevant for large files and would * need some kind of string popularity to be effective though. */ stringTable.insert(pair, stringTable.size()); } } else { auto const reference = stringTable.size() - iter.value(); Q_ASSERT(reference >= 0); writeUnsigned(reference, stream); } } void O5mWriter::writeSigned(qint64 value, QDataStream &stream) const { bool const negative = value < 0; if (negative) { value = -value - 1; } quint8 word = (value >> 6) > 0 ? (1<<7) : 0; word |= ( (value << 1) & 0x7e); if (negative) { word |= 0x01; } value >>= 6; stream << word; while (value > 0) { word = ((value >> 7) > 0 ? 0x80 : 0x00) | (value & 0x7f); stream << word; value >>= 7; } } void O5mWriter::writeUnsigned(quint32 value, QDataStream &stream) const { do { quint8 word = ((value >> 7) > 0 ? 0x80 : 0x00) | (value & 0x7f); stream << word; value >>= 7; } while (value > 0); } qint32 O5mWriter::deltaTo(double value, double previous) const { double const diff = value - previous; return qRound(diff * 1e7); } MARBLE_ADD_WRITER(O5mWriter, "o5m") } diff --git a/src/plugins/runner/osm/translators/OsmConverter.cpp b/src/plugins/runner/osm/translators/OsmConverter.cpp index 7fef42075..8131ef0ea 100644 --- a/src/plugins/runner/osm/translators/OsmConverter.cpp +++ b/src/plugins/runner/osm/translators/OsmConverter.cpp @@ -1,115 +1,109 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Dennis Nienhüser // //Self #include "OsmDocumentTagTranslator.h" //Marble #include "OsmNodeTagWriter.h" #include "OsmWayTagWriter.h" #include "OsmElementDictionary.h" #include "GeoDataDocument.h" #include "GeoWriter.h" #include "GeoDataPlacemark.h" #include "GeoDataGeometry.h" #include "GeoDataPoint.h" #include "GeoDataPolygon.h" #include "GeoDataRelation.h" #include "GeoDataLinearRing.h" -#include "GeoDataTypes.h" #include "osm/OsmPlacemarkData.h" #include "osm/OsmObjectManager.h" #include "OsmRelationTagWriter.h" #include namespace Marble { void OsmConverter::read(const GeoDataDocument *document) { m_nodes.clear(); m_ways.clear(); m_relations.clear(); // Writing all the component nodes ( points, nodes of polylines, nodes of polygons ) for (auto feature: document->featureList()) { - if (feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - GeoDataPlacemark* placemark = static_cast(feature); + if (auto placemark = geodata_cast(feature)) { // If the placemark's osmData is not complete, it is initialized by the OsmObjectManager OsmObjectManager::initializeOsmData( placemark ); const OsmPlacemarkData & osmData = placemark->osmData(); - if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPointType ) { + if (geodata_cast(placemark->geometry())) { m_nodes << OsmConverter::Node(placemark->coordinate(), osmData); - } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType ) { - const GeoDataLineString* lineString = static_cast( placemark->geometry() ); + } else if (const auto lineString = geodata_cast(placemark->geometry())) { for (auto const &coordinates: *lineString) { m_nodes << OsmConverter::Node(coordinates, osmData.nodeReference(coordinates)); } m_ways << OsmConverter::Way(lineString, osmData); - } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataLinearRingType ) { - const GeoDataLinearRing* linearRing = static_cast( placemark->geometry() ); + } else if (const auto linearRing = geodata_cast(placemark->geometry())) { for (auto const &coordinates: *linearRing) { m_nodes << OsmConverter::Node(coordinates, osmData.nodeReference(coordinates)); } m_ways << OsmConverter::Way(linearRing, osmData); - } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) { - const GeoDataPolygon *polygon = static_cast( placemark->geometry() ); + } else if (const auto polygon = geodata_cast(placemark->geometry())) { int index = -1; // Writing all the outerRing's nodes const GeoDataLinearRing &outerRing = polygon->outerBoundary(); const OsmPlacemarkData outerRingOsmData = osmData.memberReference( index ); for (auto const &coordinates: outerRing) { m_nodes << OsmConverter::Node(coordinates, outerRingOsmData.nodeReference(coordinates)); } m_ways << OsmConverter::Way(&outerRing, outerRingOsmData); // Writing all nodes for each innerRing for (auto const &innerRing: polygon->innerBoundaries() ) { ++index; const OsmPlacemarkData innerRingOsmData = osmData.memberReference( index ); for (auto const &coordinates: innerRing) { m_nodes << OsmConverter::Node(coordinates, innerRingOsmData.nodeReference(coordinates)); } m_ways << OsmConverter::Way(&innerRing, innerRingOsmData); } m_relations.append(OsmConverter::Relation(placemark, osmData)); } - } else if (feature->nodeType() == GeoDataTypes::GeoDataRelationType) { - GeoDataRelation* placemark = static_cast(feature); + } else if (const auto placemark = geodata_cast(feature)) { m_relations.append(OsmConverter::Relation(placemark, placemark->osmData())); } } // Sort by id ascending since some external tools rely on that std::sort(m_nodes.begin(), m_nodes.end(), [] (const Node &a, const Node &b) { return a.second.id() < b.second.id(); }); std::sort(m_ways.begin(), m_ways.end(), [] (const Way &a, const Way &b) { return a.second.id() < b.second.id(); }); std::sort(m_relations.begin(), m_relations.end(), [] (const Relation &a, const Relation &b) { return a.second.id() < b.second.id(); }); } const OsmConverter::Nodes &OsmConverter::nodes() const { return m_nodes; } const OsmConverter::Ways &OsmConverter::ways() const { return m_ways; } const OsmConverter::Relations &OsmConverter::relations() const { return m_relations; } } diff --git a/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp b/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp index bdb5663d1..376044633 100644 --- a/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp +++ b/src/plugins/runner/osm/translators/OsmDocumentTagTranslator.cpp @@ -1,70 +1,69 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Stanciu Marius-Valeriu // //Self #include "OsmDocumentTagTranslator.h" //Marble #include "OsmNodeTagWriter.h" #include "OsmWayTagWriter.h" #include "OsmElementDictionary.h" #include "GeoDataDocument.h" #include "GeoWriter.h" #include "GeoDataGeometry.h" #include "GeoDataPoint.h" #include "GeoDataPolygon.h" #include "GeoDataPlacemark.h" #include "GeoDataLinearRing.h" #include "GeoDataTypes.h" #include "osm/OsmPlacemarkData.h" #include "osm/OsmObjectManager.h" #include "OsmRelationTagWriter.h" #include "OsmConverter.h" #include namespace Marble { static GeoTagWriterRegistrar s_writerDocument( GeoTagWriter::QualifiedName( GeoDataTypes::GeoDataDocumentType, osm::osmTag_version06 ), new OsmDocumentTagTranslator() ); bool OsmDocumentTagTranslator::write( const GeoNode *node, GeoWriter& writer ) const { const GeoDataDocument *document = static_cast(node); OsmConverter converter; converter.read(document); OsmNodeTagWriter::writeAllNodes(converter.nodes(), writer); qint64 lastId = 0; for (auto const &way: converter.ways()) { if (way.second.id() != lastId) { OsmWayTagWriter::writeWay(*way.first, way.second, writer); lastId = way.second.id(); } } for (auto const & relation: converter.relations()) { - if (relation.first->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - auto placemark = static_cast(relation.first); - Q_ASSERT(placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType); - auto polygon = static_cast(placemark->geometry()); + if (auto placemark = geodata_cast(relation.first)) { + auto polygon = geodata_cast(placemark->geometry()); + Q_ASSERT(polygon); OsmRelationTagWriter::writeMultipolygon(*polygon, relation.second, writer ); } } return true; } } diff --git a/src/thumbnailer/thumbnailer.cpp b/src/thumbnailer/thumbnailer.cpp index b5eebcba9..d1e855da6 100644 --- a/src/thumbnailer/thumbnailer.cpp +++ b/src/thumbnailer/thumbnailer.cpp @@ -1,140 +1,141 @@ // Copyright 2014 Friedrich W. H. Kossebau // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this program. If not, see . #include "thumbnailer.h" // Marble #include #include #include #include #include #include #include -#include + // Qt #include static const int timeoutTime = 5000; // in msec namespace Marble { GeoDataThumbnailer::GeoDataThumbnailer() : ThumbCreator() , m_marbleMap() { m_marbleMap.setMapThemeId(QStringLiteral("earth/openstreetmap/openstreetmap.dgml")); m_marbleMap.setProjection(Equirectangular); m_marbleMap.setMapQualityForViewContext( PrintQuality, Still ); m_marbleMap.setViewContext( Still ); for( RenderPlugin* plugin: m_marbleMap.renderPlugins() ) { plugin->setEnabled( false ); } m_outtimer.setInterval(timeoutTime); m_outtimer.setSingleShot(true); connect(&m_outtimer, SIGNAL(timeout()), &m_eventLoop, SLOT(quit())); } GeoDataThumbnailer::~GeoDataThumbnailer() { } bool GeoDataThumbnailer::create(const QString &path, int width, int height, QImage &image) { m_marbleMap.setSize(width, height); MarbleModel *const model = m_marbleMap.model(); // load the document content m_loadingCompleted = false; m_currentFilename = path; connect(model->treeModel(), SIGNAL(added(GeoDataObject*)), this, SLOT(onGeoDataObjectAdded(GeoDataObject*))); model->addGeoDataFile(path); if (! m_loadingCompleted) { // loading is done async, so wait here for a while // Using a QEventLoop here seems fine, thumbnailers are only used inside the // thumbnail protocol slave, it seems m_outtimer.start(); m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); } if (m_loadingCompleted) { // TODO: limit to shown map, if full earth is used image = QImage(width, height, QImage::Format_ARGB32); image.fill(qRgba(0, 0, 0, 0)); // Create a painter that will do the painting. GeoPainter geoPainter( &image, m_marbleMap.viewport(), m_marbleMap.mapQuality() ); m_marbleMap.paint( geoPainter, QRect() ); // TODO: dirtyRect seems currently unused, make sure it is } disconnect(model->treeModel(), SIGNAL(added(GeoDataObject*)), this, SLOT(onGeoDataObjectAdded(GeoDataObject*))); model->removeGeoData(path); m_currentFilename.clear(); return m_loadingCompleted; } static qreal radius(qreal zoom) { return pow(M_E, (zoom / 200.0)); } void GeoDataThumbnailer::onGeoDataObjectAdded( GeoDataObject* object ) { - if ( object->nodeType() != GeoDataTypes::GeoDataDocumentType ) { + const auto document = geodata_cast(object); + + if (!document) { return; } - const GeoDataDocument *document = static_cast(object); if (document->fileName() != m_currentFilename) { return; } const GeoDataLatLonAltBox latLonAltBox = document->latLonAltBox(); const GeoDataCoordinates center = latLonAltBox.center(); int newRadius = m_marbleMap.radius(); //prevent divide by zero if( latLonAltBox.height() && latLonAltBox.width() ) { const ViewportParams* viewparams = m_marbleMap.viewport(); //work out the needed zoom level const int horizontalRadius = ( 0.25 * M_PI ) * ( viewparams->height() / latLonAltBox.height() ); const int verticalRadius = ( 0.25 * M_PI ) * ( viewparams->width() / latLonAltBox.width() ); newRadius = qMin( horizontalRadius, verticalRadius ); newRadius = qMax(radius(m_marbleMap.minimumZoom()), qMin(newRadius, radius(m_marbleMap.maximumZoom()))); } m_marbleMap.centerOn( center.longitude(GeoDataCoordinates::Degree), center.latitude(GeoDataCoordinates::Degree) ); m_marbleMap.setRadius( newRadius ); m_loadingCompleted = true; m_outtimer.stop(); m_eventLoop.quit(); } ThumbCreator::Flags GeoDataThumbnailer::flags() const { return DrawFrame; } } diff --git a/tests/TestGeoData.cpp b/tests/TestGeoData.cpp index 79d09f3aa..4dce689e3 100644 --- a/tests/TestGeoData.cpp +++ b/tests/TestGeoData.cpp @@ -1,138 +1,137 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2009 Bastian Holst // #include #include #include "GeoDataDocument.h" #include "GeoDataFolder.h" #include "GeoDataPlacemark.h" #include "GeoDataCoordinates.h" #include "GeoDataLatLonAltBox.h" #include "GeoDataTypes.h" #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include "GeoDataStyleMap.h" #include "MarbleDebug.h" namespace Marble { class TestGeoData : public QObject { Q_OBJECT private Q_SLOTS: void nodeTypeTest(); void parentingTest(); }; /// test the nodeType function through various construction tests void TestGeoData::nodeTypeTest() { /// basic testing of nodeType GeoDataFolder *folder = new GeoDataFolder; const char* folderType = GeoDataTypes::GeoDataFolderType; QCOMPARE( folder->nodeType(), folderType ); /// testing the nodeType of an object appended to a container GeoDataDocument document; document.append( folder ); GeoDataFeature &featureRef = document.last(); - QCOMPARE( featureRef.nodeType(), folderType ); - QCOMPARE( static_cast(&featureRef)->nodeType(), folderType ); + QVERIFY(geodata_cast(&featureRef)); } void TestGeoData::parentingTest() { GeoDataDocument *document = new GeoDataDocument; GeoDataFolder *folder = new GeoDataFolder; /// simple parenting test GeoDataPlacemark *placemark = new GeoDataPlacemark; placemark->setParent(document); QCOMPARE(placemark->parent(), document); /// simple append and child count test document->append(placemark); /// appending folder to document before feeding folder document->append(folder); QCOMPARE(document->size(), 2); GeoDataPlacemark *placemark2 = new GeoDataPlacemark; folder->append(placemark2); QCOMPARE(folder->size(), 1); /// retrieve child and check it matches placemark GeoDataPlacemark *placemarkPtr; - QCOMPARE(document->child(0)->nodeType(), placemark->nodeType()); + QVERIFY(geodata_cast(document->child(0))); placemarkPtr = static_cast(document->child(0)); QCOMPARE(placemarkPtr, placemark); /// check retrieved placemark matches intented child int position = document->childPosition(placemarkPtr); QCOMPARE(position, 0); /// retrieve child two and check it matches folder GeoDataFolder *folderPtr; - QCOMPARE(document->child(1)->nodeType(), folder->nodeType()); + QVERIFY(geodata_cast(document->child(1))); folderPtr = static_cast(document->child(1)); QCOMPARE(folderPtr, folder); /// check retrieved folder matches intended child position = document->childPosition(folderPtr); QCOMPARE(position, 1); /// retrieve child three and check it matches placemark QCOMPARE(folderPtr->size(), 1); placemarkPtr = static_cast(folderPtr->child(0)); QCOMPARE(placemarkPtr->nodeType(), placemark2->nodeType()); QCOMPARE(placemarkPtr, placemark2); /// check retrieved placemark matches intended child QCOMPARE(folderPtr->childPosition(placemarkPtr), 0); /// Set a style GeoDataIconStyle iconStyle; iconStyle.setIconPath( "myicon.png" ); GeoDataStyle::Ptr style(new GeoDataStyle); style->setId( "mystyle" ); style->setIconStyle( iconStyle ); GeoDataObject* noParent = 0; QCOMPARE( style->parent(), noParent ); QCOMPARE( iconStyle.parent(), noParent ); document->setStyle( style ); QCOMPARE( style->parent(), document ); // Parent should be assigned now QCOMPARE( style->iconStyle().parent(), style.data() ); QCOMPARE( iconStyle.parent(), noParent ); // setIconStyle copies QCOMPARE( placemark->style()->parent(), noParent ); placemark->setStyle( style ); QCOMPARE( placemark->style()->parent(), placemark ); // Parent should be assigned now /// Set a style map GeoDataStyleMap* styleMap = new GeoDataStyleMap; styleMap->setId( "mystylemap" ); styleMap->insert( "normal", "#mystyle" ); styleMap->insert( "highlight", "#mystyle" ); document->addStyle( style ); document->setStyleMap( styleMap ); QCOMPARE( placemark2->style()->parent(), noParent ); placemark2->setStyleUrl( "#mystyle" ); QCOMPARE( placemark2->style()->parent(), document ); // Parent is document, not placemark2 QCOMPARE( iconStyle.iconPath(), QString( "myicon.png" ) ); QCOMPARE( placemark2->style()->iconStyle().iconPath(), QString( "myicon.png" ) ); } } QTEST_MAIN( Marble::TestGeoData ) #include "TestGeoData.moc" diff --git a/tools/vectorosm-tilecreator/NodeReducer.cpp b/tools/vectorosm-tilecreator/NodeReducer.cpp index 410994bd1..579049e24 100644 --- a/tools/vectorosm-tilecreator/NodeReducer.cpp +++ b/tools/vectorosm-tilecreator/NodeReducer.cpp @@ -1,194 +1,190 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Akshat Tandon // #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" #include "GeoDataLineString.h" #include "GeoDataPolygon.h" #include "GeoDataCoordinates.h" #include "MarbleMath.h" #include "NodeReducer.h" #include "OsmPlacemarkData.h" #include #include namespace Marble { NodeReducer::NodeReducer(GeoDataDocument* document, const TileId &tileId) : m_removedNodes(0), m_remainingNodes(0), m_zoomLevel(tileId.zoomLevel()) { const GeoSceneMercatorTileProjection tileProjection; GeoDataLatLonBox tileBoundary = tileProjection.geoCoordinates(m_zoomLevel, tileId.x(), tileId.y()); tileBoundary.scale(1.0-1e-4, 1.0-1e-4); tileBoundary.boundaries(m_tileBoundary[North], m_tileBoundary[South], m_tileBoundary[East], m_tileBoundary[West]); for (GeoDataPlacemark* placemark: document->placemarkList()) { GeoDataGeometry const * const geometry = placemark->geometry(); auto const visualCategory = placemark->visualCategory(); - if(geometry->nodeType() == GeoDataTypes::GeoDataLineStringType) { - GeoDataLineString const * prevLine = static_cast(geometry); + if (const auto prevLine = geodata_cast(geometry)) { GeoDataLineString* reducedLine = new GeoDataLineString; reduce(*prevLine, placemark->osmData(), visualCategory, reducedLine); placemark->setGeometry(reducedLine); } else if (m_zoomLevel < 17) { - if(geometry->nodeType() == GeoDataTypes::GeoDataLinearRingType) { - GeoDataLinearRing const * prevRing = static_cast(geometry); + if (const auto prevRing = geodata_cast(geometry)) { GeoDataLinearRing* reducedRing = new GeoDataLinearRing; reduce(*prevRing, placemark->osmData(), visualCategory, reducedRing); placemark->setGeometry(reducedRing); - } else if(geometry->nodeType() == GeoDataTypes::GeoDataPolygonType) { + } else if (const auto prevPolygon = geodata_cast(geometry)) { GeoDataPolygon* reducedPolygon = new GeoDataPolygon; - GeoDataPolygon const * prevPolygon = static_cast(geometry); GeoDataLinearRing const * prevRing = &(prevPolygon->outerBoundary()); GeoDataLinearRing reducedRing; reduce(*prevRing, placemark->osmData().memberReference(-1), visualCategory, &reducedRing); reducedPolygon->setOuterBoundary(reducedRing); QVector const & innerBoundaries = prevPolygon->innerBoundaries(); for(int i = 0; i < innerBoundaries.size(); i++) { prevRing = &innerBoundaries[i]; GeoDataLinearRing reducedInnerRing; reduce(*prevRing, placemark->osmData().memberReference(i), visualCategory, &reducedInnerRing); reducedPolygon->appendInnerBoundary(reducedInnerRing); } placemark->setGeometry(reducedPolygon); } } } } qint64 NodeReducer::remainingNodes() const { return m_remainingNodes; } qreal NodeReducer::epsilonFor(qreal multiplier) const { if (m_zoomLevel >= 17) { return 0.25; } else if (m_zoomLevel >= 10) { int const factor = 1 << (qAbs(m_zoomLevel-12)); return multiplier / factor; } else { int const factor = 1 << (qAbs(m_zoomLevel-10)); return multiplier * factor; } } qreal NodeReducer::perpendicularDistance(const GeoDataCoordinates &a, const GeoDataCoordinates &b, const GeoDataCoordinates &c) const { qreal ret; qreal const y0 = a.latitude(); qreal const x0 = a.longitude(); qreal const y1 = b.latitude(); qreal const x1 = b.longitude(); qreal const y2 = c.latitude(); qreal const x2 = c.longitude(); qreal const y01 = x0 - x1; qreal const x01 = y0 - y1; qreal const y10 = x1 - x0; qreal const x10 = y1 - y0; qreal const y21 = x2 - x1; qreal const x21 = y2 - y1; qreal const len = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); qreal const t = len == 0.0 ? -1.0 : (x01 * x21 + y01 * y21) / len; if ( t < 0.0 ) { ret = EARTH_RADIUS * distanceSphere(a, b); } else if ( t > 1.0 ) { ret = EARTH_RADIUS * distanceSphere(a, c); } else { qreal const nom = qAbs( x21 * y10 - x10 * y21 ); qreal const den = sqrt( x21 * x21 + y21 * y21 ); ret = EARTH_RADIUS * nom / den; } return ret; } bool NodeReducer::touchesTileBorder(const GeoDataCoordinates &coordinates) const { return coordinates.latitude() >= m_tileBoundary[North] || coordinates.latitude() <= m_tileBoundary[South] || coordinates.longitude() <= m_tileBoundary[West] || coordinates.longitude() >= m_tileBoundary[East]; } qint64 NodeReducer::removedNodes() const { return m_removedNodes; } void NodeReducer::setBorderPoints(OsmPlacemarkData &osmData, const QVector &borderPoints, int length) const { int const n = borderPoints.size(); if (n == 0) { return; } if (n > length) { qDebug() << "Invalid border points for length" << length << ":" << borderPoints; return; } typedef QPair Segment; typedef QVector Segments; Segments segments; Segment currentSegment; currentSegment.first = borderPoints.first(); currentSegment.second = currentSegment.first; for (int i=1; i 1 && segments.last().second+1 == length && segments.first().first == 0) { segments.last().second = segments.first().second; segments.pop_front(); } int wraps = 0; for (auto const &segment: segments) { if (segment.first >= segment.second) { ++wraps; } if (segment.first < 0 || segment.second < 0 || segment.first+1 > length || segment.second+1 > length) { qDebug() << "Wrong border points sequence for length " << length << ":" << borderPoints << ", intermediate " << segments; return; } } if (wraps > 1) { //qDebug() << "Wrong border points sequence:" << borderPoints; return; } QString value; value.reserve(segments.size() * (2 + QString::number(length).size())); for (auto const &segment: segments) { int diff = segment.second - segment.first; diff = diff > 0 ? diff : length + diff; value = value % QStringLiteral(";") % QString::number(segment.first) % QStringLiteral("+") % QString::number(diff); } osmData.addTag(QStringLiteral("mx:bp"), value.mid(1)); } } diff --git a/tools/vectorosm-tilecreator/TagsFilter.cpp b/tools/vectorosm-tilecreator/TagsFilter.cpp index dc0e9b7c2..d625e0107 100644 --- a/tools/vectorosm-tilecreator/TagsFilter.cpp +++ b/tools/vectorosm-tilecreator/TagsFilter.cpp @@ -1,113 +1,111 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Akshat Tandon // #include #include #include "TagsFilter.h" #include "GeoDataObject.h" #include "GeoDataDocument.h" #include "OsmPlacemarkData.h" #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" namespace Marble { TagsFilter::TagsFilter(GeoDataDocument *document, const Tags &tagsList, FilterFlag filterFlag) : m_accepted(new GeoDataDocument) { for (GeoDataFeature *feature: document->featureList()) { - if (feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - GeoDataPlacemark* placemark = static_cast(feature); + if (const auto placemark = geodata_cast(feature)) { bool acceptPlacemark = false; auto const & osmData = placemark->osmData(); if (filterFlag == FilterRailwayService && osmData.containsTagKey(QStringLiteral("railway")) && osmData.containsTagKey(QStringLiteral("service"))) { acceptPlacemark = false; } else { for (auto const &tag: tagsList) { bool contains; if (tag.second == QLatin1String("*")) { contains = osmData.containsTagKey(tag.first); } else { contains = osmData.containsTag(tag.first, tag.second); } if (contains) { acceptPlacemark = true; break; } } } if (acceptPlacemark) { m_accepted->append(placemark->clone()); } else { m_rejectedObjects.append(placemark->clone()); } } else { m_accepted->append(feature->clone()); } } } TagsFilter::~TagsFilter() { delete m_accepted; qDeleteAll(m_rejectedObjects); } QVector::const_iterator TagsFilter::rejectedObjectsBegin() const { return m_rejectedObjects.begin(); } QVector::const_iterator TagsFilter::rejectedObjectsEnd() const { return m_rejectedObjects.end(); } GeoDataDocument *TagsFilter::accepted() { return m_accepted; } void TagsFilter::removeAnnotationTags(GeoDataDocument *document) { for (auto placemark: document->placemarkList()) { auto & osmData = placemark->osmData(); removeAnnotationTags(osmData); for (auto & reference: osmData.nodeReferences()) { removeAnnotationTags(reference); } for (auto & reference: osmData.memberReferences()) { removeAnnotationTags(reference); } } } void TagsFilter::removeAnnotationTags(OsmPlacemarkData &osmData) { osmData.removeTag(QLatin1String("comment")); osmData.removeTag(QLatin1String("note")); osmData.removeTag(QLatin1String("note:de")); osmData.removeTag(QLatin1String("fixme")); osmData.removeTag(QLatin1String("todo")); osmData.removeTag(QLatin1String("source")); osmData.removeTag(QLatin1String("source:geometry")); osmData.removeTag(QLatin1String("source:name")); osmData.removeTag(QLatin1String("source:addr")); osmData.removeTag(QLatin1String("source:ref")); osmData.removeTag(QLatin1String("source_ref")); } } diff --git a/tools/vectorosm-tilecreator/VectorClipper.cpp b/tools/vectorosm-tilecreator/VectorClipper.cpp index b7051b47d..b682fe2b3 100644 --- a/tools/vectorosm-tilecreator/VectorClipper.cpp +++ b/tools/vectorosm-tilecreator/VectorClipper.cpp @@ -1,337 +1,335 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Dennis Nienhüser // Copyright 2016 David Kolozsvari // #include "VectorClipper.h" #include "TileId.h" -#include "GeoDataTypes.h" #include "GeoDataLatLonAltBox.h" #include "GeoDataPolygon.h" #include "GeoDataPlacemark.h" #include "GeoDataRelation.h" #include "OsmPlacemarkData.h" #include "OsmObjectManager.h" #include "TileCoordsPyramid.h" #include "clipper/clipper.hpp" #include #include #include #include namespace Marble { VectorClipper::VectorClipper(GeoDataDocument* document, int maxZoomLevel) : m_maxZoomLevel(maxZoomLevel) { for (auto feature: document->featureList()) { - if (feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - GeoDataPlacemark* placemark = static_cast(feature); + if (const auto placemark = geodata_cast(feature)) { // Select zoom level such that the placemark fits in a single tile int zoomLevel; qreal north, south, east, west; placemark->geometry()->latLonAltBox().boundaries(north, south, east, west); for (zoomLevel = maxZoomLevel; zoomLevel >= 0; --zoomLevel) { if (TileId::fromCoordinates(GeoDataCoordinates(west, north), zoomLevel) == TileId::fromCoordinates(GeoDataCoordinates(east, south), zoomLevel)) { break; } } TileId const key = TileId::fromCoordinates(GeoDataCoordinates(west, north), zoomLevel); m_items[key] << placemark; - } else if (feature->nodeType() == GeoDataTypes::GeoDataRelationType) { - m_relations << static_cast(feature); + } else if (GeoDataRelation *relation = geodata_cast(feature)) { + m_relations << relation; } else { Q_ASSERT(false && "only placemark variants are supported so far"); } } } GeoDataDocument *VectorClipper::clipTo(const GeoDataLatLonBox &tileBoundary, int zoomLevel) { bool const filterSmallAreas = zoomLevel > 10 && zoomLevel < 17; GeoDataDocument* tile = new GeoDataDocument(); auto const clip = clipPath(tileBoundary, zoomLevel); GeoDataLinearRing ring; ring << GeoDataCoordinates(tileBoundary.west(), tileBoundary.north()); ring << GeoDataCoordinates(tileBoundary.east(), tileBoundary.north()); ring << GeoDataCoordinates(tileBoundary.east(), tileBoundary.south()); ring << GeoDataCoordinates(tileBoundary.west(), tileBoundary.south()); qreal const minArea = filterSmallAreas ? 0.01 * area(ring) : 0.0; QSet osmIds; for (GeoDataPlacemark const * placemark: potentialIntersections(tileBoundary)) { GeoDataGeometry const * const geometry = placemark ? placemark->geometry() : nullptr; if (geometry && tileBoundary.intersects(geometry->latLonAltBox())) { - if(geometry->nodeType() == GeoDataTypes::GeoDataPolygonType) { + if (geodata_cast(geometry)) { clipPolygon(placemark, clip, minArea, tile, osmIds); - } else if (geometry->nodeType() == GeoDataTypes::GeoDataLineStringType) { + } else if (geodata_cast(geometry)) { clipString(placemark, clip, minArea, tile, osmIds); - } else if (geometry->nodeType() == GeoDataTypes::GeoDataLinearRingType) { + } else if (geodata_cast(geometry)) { clipString(placemark, clip, minArea, tile, osmIds); } else { tile->append(placemark->clone()); osmIds << placemark->osmData().id(); } } } for (auto relation: m_relations) { if (relation->containsAnyOf(osmIds)) { GeoDataRelation* multi = new GeoDataRelation; multi->osmData() = relation->osmData(); tile->append(multi); } } return tile; } QVector VectorClipper::potentialIntersections(const GeoDataLatLonBox &box) const { qreal north, south, east, west; box.boundaries(north, south, east, west); TileId const topLeft = TileId::fromCoordinates(GeoDataCoordinates(west, north), m_maxZoomLevel); TileId const bottomRight = TileId::fromCoordinates(GeoDataCoordinates(east, south), m_maxZoomLevel); QRect rect; rect.setCoords(topLeft.x(), topLeft.y(), bottomRight.x(), bottomRight.y()); TileCoordsPyramid pyramid(0, m_maxZoomLevel); pyramid.setBottomLevelCoords(rect); QVector result; for (int level = pyramid.topLevel(), maxLevel = pyramid.bottomLevel(); level <= maxLevel; ++level) { int x1, y1, x2, y2; pyramid.coords(level).getCoords(&x1, &y1, &x2, &y2); for (int x = x1; x <= x2; ++x) { for (int y = y1; y <= y2; ++y) { result << m_items.value(TileId(0, level, x, y)); } } } return result; } GeoDataDocument *VectorClipper::clipTo(unsigned int zoomLevel, unsigned int tileX, unsigned int tileY) { const GeoDataLatLonBox tileBoundary = m_tileProjection.geoCoordinates(zoomLevel, tileX, tileY); GeoDataDocument *tile = clipTo(tileBoundary, zoomLevel); QString tileName = QString("%1/%2/%3").arg(zoomLevel).arg(tileX).arg(tileY); tile->setName(tileName); return tile; } ClipperLib::Path VectorClipper::clipPath(const GeoDataLatLonBox &box, int zoomLevel) const { using namespace ClipperLib; Path path; int const steps = qMax(1, 22 - 2 * zoomLevel); qreal const scale = IntPoint::scale; double x = box.west() * scale; double const horizontalStep = (box.east() * scale - x) / steps; double y = box.north() * scale; double const verticalStep = (box.south() * scale - y) / steps; for (int i=0; i= GeoDataPlacemark::HighwaySteps && visualCategory <= GeoDataPlacemark::HighwayMotorway) { return false; } if (visualCategory >= GeoDataPlacemark::RailwayRail && visualCategory <= GeoDataPlacemark::RailwayFunicular) { return false; } if (visualCategory >= GeoDataPlacemark::AdminLevel1 && visualCategory <= GeoDataPlacemark::AdminLevel11) { return false; } if (visualCategory == GeoDataPlacemark::BoundaryMaritime || visualCategory == GeoDataPlacemark::InternationalDateLine) { return false; } return true; } qreal VectorClipper::area(const GeoDataLinearRing &ring) { auto const iter = m_areas.find(&ring); if (iter != m_areas.end()) { return *iter; } int const n = ring.size(); qreal area = 0; if (n<3) { return area; } for (int i = 1; i < n; ++i ){ area += (ring[i].longitude() - ring[i-1].longitude() ) * ( ring[i].latitude() + ring[i-1].latitude()); } area += (ring[0].longitude() - ring[n-1].longitude() ) * (ring[0].latitude() + ring[n-1].latitude()); qreal const result = EARTH_RADIUS * EARTH_RADIUS * qAbs(area * 0.5); m_areas.insert(&ring, result); return result; } void VectorClipper::getBounds(const ClipperLib::Path &path, ClipperLib::cInt &minX, ClipperLib::cInt &maxX, ClipperLib::cInt &minY, ClipperLib::cInt &maxY) const { Q_ASSERT(!path.empty()); minX = path[0].X; maxX = minX; minY = path[0].Y; maxY = minY; for (auto const & point: path) { if (point.X < minX) { minX = point.X; } else if (point.X > maxX) { maxX = point.X; } if (point.Y < minY) { minY = point.Y; } else if (point.Y > maxY) { maxY = point.Y; } } } void VectorClipper::clipPolygon(const GeoDataPlacemark *placemark, const ClipperLib::Path &tileBoundary, qreal minArea, GeoDataDocument *document, QSet &osmIds) { const GeoDataPolygon* polygon = static_cast(placemark->geometry()); if (minArea > 0.0 && area(polygon->outerBoundary()) < minArea) { return; } using namespace ClipperLib; Path path; for(auto const & node: polygon->outerBoundary()) { path << IntPoint(&node); } cInt minX, maxX, minY, maxY; getBounds(tileBoundary, minX, maxX, minY, maxY); Clipper clipper; clipper.PreserveCollinear(true); clipper.AddPath(tileBoundary, ptClip, true); clipper.AddPath(path, ptSubject, true); Paths paths; clipper.Execute(ctIntersection, paths); for(const auto &path: paths) { GeoDataPlacemark* newPlacemark = new GeoDataPlacemark; newPlacemark->setVisible(placemark->isVisible()); newPlacemark->setVisualCategory(placemark->visualCategory()); GeoDataLinearRing outerRing; OsmPlacemarkData const & placemarkOsmData = placemark->osmData(); OsmPlacemarkData & newPlacemarkOsmData = newPlacemark->osmData(); int index = -1; OsmPlacemarkData const & outerRingOsmData = placemarkOsmData.memberReference(index); OsmPlacemarkData & newOuterRingOsmData = newPlacemarkOsmData.memberReference(index); int nodeIndex = 0; for(const auto &point: path) { GeoDataCoordinates const coordinates = point.coordinates(); outerRing << coordinates; auto const originalOsmData = outerRingOsmData.nodeReference(coordinates); if (originalOsmData.id() > 0) { newOuterRingOsmData.addNodeReference(coordinates, originalOsmData); } ++nodeIndex; } GeoDataPolygon* newPolygon = new GeoDataPolygon; newPolygon->setOuterBoundary(outerRing); newPlacemark->setGeometry(newPolygon); if (placemarkOsmData.id() > 0) { newPlacemarkOsmData.addTag(QStringLiteral("mx:oid"), QString::number(placemarkOsmData.id())); } copyTags(placemarkOsmData, newPlacemarkOsmData); copyTags(outerRingOsmData, newOuterRingOsmData); if (outerRingOsmData.id() > 0) { newOuterRingOsmData.addTag(QStringLiteral("mx:oid"), QString::number(outerRingOsmData.id())); } auto const & innerBoundaries = polygon->innerBoundaries(); for (index = 0; index < innerBoundaries.size(); ++index) { auto const & innerBoundary = innerBoundaries.at(index); if (minArea > 0.0 && area(innerBoundary) < minArea) { continue; } auto const & innerRingOsmData = placemarkOsmData.memberReference(index); clipper.Clear(); clipper.AddPath(path, ptClip, true); Path innerPath; for(auto const & node: innerBoundary) { innerPath << IntPoint(&node); } clipper.AddPath(innerPath, ptSubject, true); Paths innerPaths; clipper.Execute(ctIntersection, innerPaths); for(auto const &innerPath: innerPaths) { int const newIndex = newPolygon->innerBoundaries().size(); auto & newInnerRingOsmData = newPlacemarkOsmData.memberReference(newIndex); GeoDataLinearRing innerRing; nodeIndex = 0; for(const auto &point: innerPath) { GeoDataCoordinates const coordinates = point.coordinates(); innerRing << coordinates; auto const originalOsmData = innerRingOsmData.nodeReference(coordinates); if (originalOsmData.id() > 0) { newInnerRingOsmData.addNodeReference(coordinates, originalOsmData); } ++nodeIndex; } newPolygon->appendInnerBoundary(innerRing); if (innerRingOsmData.id() > 0) { newInnerRingOsmData.addTag(QStringLiteral("mx:oid"), QString::number(innerRingOsmData.id())); } copyTags(innerRingOsmData, newInnerRingOsmData); } } OsmObjectManager::initializeOsmData(newPlacemark); document->append(newPlacemark); osmIds << placemark->osmData().id(); } } void VectorClipper::copyTags(const GeoDataPlacemark &source, GeoDataPlacemark &target) const { copyTags(source.osmData(), target.osmData()); } void VectorClipper::copyTags(const OsmPlacemarkData &originalPlacemarkData, OsmPlacemarkData &targetOsmData) const { for (auto iter=originalPlacemarkData.tagsBegin(), end=originalPlacemarkData.tagsEnd(); iter != end; ++iter) { targetOsmData.addTag(iter.key(), iter.value()); } } } diff --git a/tools/vectorosm-tilecreator/WayConcatenator.cpp b/tools/vectorosm-tilecreator/WayConcatenator.cpp index b5d5a953e..7e1a31f44 100644 --- a/tools/vectorosm-tilecreator/WayConcatenator.cpp +++ b/tools/vectorosm-tilecreator/WayConcatenator.cpp @@ -1,244 +1,242 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Akshat Tandon // #include #include #include -#include "GeoDataTypes.h" #include "GeoDataPlacemark.h" #include "GeoDataDocument.h" #include "GeoDataObject.h" #include "GeoDataLineString.h" #include "OsmPlacemarkData.h" #include "StyleBuilder.h" #include "OsmObjectManager.h" #include "WayConcatenator.h" #include "WayChunk.h" #include "TagsFilter.h" namespace Marble { WayConcatenator::WayConcatenator(GeoDataDocument *document) : m_originalWays(0), m_mergedWays(0) { typedef QSharedPointer PlacemarkPtr; for (GeoDataFeature *feature: document->featureList()) { - if (feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType) { - GeoDataPlacemark* original = static_cast(feature); + if (const auto original = geodata_cast(feature)) { bool isWay = false; - if (original->geometry()->nodeType() == GeoDataTypes::GeoDataLineStringType) { + if (geodata_cast(original->geometry())) { PlacemarkPtr placemark = PlacemarkPtr(new GeoDataPlacemark(*original)); OsmObjectManager::initializeOsmData(placemark.data()); OsmPlacemarkData const & osmData = placemark->osmData(); isWay = osmData.containsTagKey("highway") || osmData.containsTagKey("railway") || osmData.containsTagKey("waterway"); if (isWay) { GeoDataLineString *line = static_cast(placemark->geometry()); qint64 firstId = osmData.nodeReference(line->first()).oid(); qint64 lastId = osmData.nodeReference(line->last()).oid(); if (firstId > 0 && lastId > 0) { ++m_originalWays; bool containsFirst = m_hash.contains(firstId); bool containsLast = m_hash.contains(lastId); if (!containsFirst && !containsLast) { createWayChunk(placemark, firstId, lastId); } else if (containsFirst && !containsLast) { auto chunk = wayChunk(*placemark, firstId); if (chunk != nullptr) { concatFirst(placemark, chunk); } else { createWayChunk(placemark, firstId, lastId); } } else if (!containsFirst && containsLast) { auto chunk = wayChunk(*placemark, lastId); if (chunk != nullptr) { concatLast(placemark, chunk); } else { createWayChunk(placemark, firstId, lastId); } } else if (containsFirst && containsLast) { auto chunk = wayChunk(*placemark, firstId); auto otherChunk = wayChunk(*placemark, lastId); if (chunk != nullptr && otherChunk != nullptr) { if(chunk == otherChunk) { m_wayPlacemarks.append(placemark); } else { concatBoth(placemark, chunk, otherChunk); } } else if(chunk != nullptr && otherChunk == nullptr) { concatFirst(placemark, chunk); } else if(chunk == nullptr && otherChunk != nullptr) { concatLast(placemark, otherChunk); } else { createWayChunk(placemark, firstId, lastId); } } } else { isWay = false; } } } if (!isWay) { m_otherPlacemarks << feature->clone(); } } else { m_otherPlacemarks << feature->clone(); } } document->clear(); for (auto placemark: m_otherPlacemarks) { document->append(placemark); } addWayChunks(document); } int WayConcatenator::originalWays() const { return m_originalWays; } int WayConcatenator::mergedWays() const { return m_mergedWays; } void WayConcatenator::addWayChunks(GeoDataDocument *document) { for (auto const &placemark: m_wayPlacemarks) { document->append(placemark->clone()); } QSet chunkSet; auto itr = m_chunks.begin(); for (; itr != m_chunks.end(); ++itr) { if (!chunkSet.contains(*itr)) { ++m_mergedWays; chunkSet.insert(*itr); PlacemarkPtr placemark = (*itr)->merge(); if (placemark) { document->append(placemark->clone()); } } } m_chunks.clear(); } void WayConcatenator::createWayChunk(const PlacemarkPtr &placemark, qint64 firstId, qint64 lastId) { WayChunk::Ptr chunk = WayChunk::Ptr(new WayChunk(placemark, firstId, lastId)); m_hash.insert(firstId, chunk); if (firstId != lastId) { m_hash.insert(lastId, chunk); } m_chunks.append(chunk); } WayChunk::Ptr WayConcatenator::wayChunk(const GeoDataPlacemark &placemark, qint64 matchId) const { QHash::ConstIterator matchItr = m_hash.find(matchId); while (matchItr != m_hash.end() && matchItr.key() == matchId) { auto const & chunk = matchItr.value(); if (chunk->concatPossible(placemark)) { return chunk; } ++matchItr; } return WayChunk::Ptr(); } void WayConcatenator::concatFirst(const PlacemarkPtr &placemark, const WayChunk::Ptr &chunk) { GeoDataLineString *line = static_cast(placemark->geometry()); qint64 firstId = placemark->osmData().nodeReference(line->first()).oid(); qint64 lastId = placemark->osmData().nodeReference(line->last()).oid(); if (chunk->first() != chunk->last()) { int chunksRemoved = m_hash.remove(firstId, chunk); Q_ASSERT(chunksRemoved == 1); } m_hash.insert(lastId, chunk); if (firstId == chunk->last()) { //First node matches with an existing last node chunk->append(placemark, lastId); } else { //First node matches with an existing first node //Reverse the GeoDataLineString of the placemark line->reverse(); chunk->prepend(placemark, lastId); } } void WayConcatenator::concatLast(const PlacemarkPtr &placemark, const WayChunk::Ptr &chunk) { GeoDataLineString *line = static_cast(placemark->geometry()); qint64 firstId = placemark->osmData().nodeReference(line->first()).oid(); qint64 lastId = placemark->osmData().nodeReference(line->last()).oid(); if (chunk->first() != chunk->last()) { int chunksRemoved = m_hash.remove(lastId, chunk); Q_ASSERT(chunksRemoved == 1); } m_hash.insert(firstId, chunk); if (lastId == chunk->first()) { chunk->prepend(placemark, firstId); } else { line->reverse(); chunk->append(placemark, firstId); } } void WayConcatenator::concatBoth(const PlacemarkPtr &placemark, const WayChunk::Ptr &chunk, const WayChunk::Ptr &otherChunk) { GeoDataLineString *line = static_cast(placemark->geometry()); qint64 firstId = placemark->osmData().nodeReference(line->first()).oid(); qint64 lastId = placemark->osmData().nodeReference(line->last()).oid(); int chunksRemoved; if (chunk->first() != chunk->last()) { chunksRemoved = m_hash.remove(firstId, chunk); Q_ASSERT(chunksRemoved == 1); } if (firstId == chunk->first()) { chunk->reverse(); } chunk->append(placemark, lastId); if (lastId == otherChunk->last()) { otherChunk->reverse(); } chunk->append(otherChunk); chunksRemoved = m_hash.remove(otherChunk->first(), otherChunk); Q_ASSERT(chunksRemoved == 1); if (otherChunk->first() != otherChunk->last()) { chunksRemoved = m_hash.remove(otherChunk->last(), otherChunk); Q_ASSERT(chunksRemoved == 1); } m_hash.insert(otherChunk->last(), chunk); m_chunks.removeOne(otherChunk); } } diff --git a/tools/vectorosm-tilecreator/vectorosm-cachetiles.cpp b/tools/vectorosm-tilecreator/vectorosm-cachetiles.cpp index ae44e70b3..554820496 100644 --- a/tools/vectorosm-tilecreator/vectorosm-cachetiles.cpp +++ b/tools/vectorosm-tilecreator/vectorosm-cachetiles.cpp @@ -1,178 +1,178 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Dennis Nienhüser // #include "GeoDataDocumentWriter.h" #include "GeoDataGeometry.h" #include "GeoDataLatLonAltBox.h" #include "GeoDataPlacemark.h" -#include "GeoDataTypes.h" +#include "GeoDataPolygon.h" #include "MarbleDirs.h" #include "MarbleModel.h" #include "MbTileWriter.h" #include "NodeReducer.h" #include "ParsingRunnerManager.h" #include "TileDirectory.h" #include "TileId.h" #include "VectorClipper.h" #include "WayConcatenator.h" #include "TileQueue.h" #include #include #include #include #include #include #include using namespace Marble; GeoDataDocument* mergeDocuments(GeoDataDocument* map1, GeoDataDocument* map2) { GeoDataDocument* mergedMap = new GeoDataDocument(*map1); OsmPlacemarkData marbleLand; marbleLand.addTag("marble_land","landmass"); for (auto placemark: map2->placemarkList()) { GeoDataPlacemark* land = new GeoDataPlacemark(*placemark); - if(land->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) { + if (geodata_cast(land->geometry())) { land->setOsmData(marbleLand); } mergedMap->append(land); } return mergedMap; } int main(int argc, char *argv[]) { QTime timer; timer.start(); QCoreApplication app(argc, argv); QCoreApplication::setApplicationName("marble-vectorosm-cachetiles"); QCoreApplication::setApplicationVersion("0.1"); QCommandLineParser parser; parser.setApplicationDescription("Create a vectorosm tile and its neighborhood"); parser.addHelpOption(); parser.addVersionOption(); parser.addPositionalArgument("tile", "The tile to create (in z/x/y.extension format)"); parser.addOptions({ {{"c", "cache-directory"}, "Directory for temporary data.", "cache", "cache"}, {{"m", "mbtile"}, "Store tiles in a mbtile database.", "mbtile"}, {"verbose", "Write progress information to standard output."} }); parser.process(app); const QStringList args = parser.positionalArguments(); if (args.size() != 1) { parser.showHelp(); return 0; } auto const input = args.first().split('/'); if (input.size() != 3) { qWarning() << "Tile" << input << "does not match the z/x/y.format convention"; parser.showHelp(); return 1; } bool canParse[] = {false, false, false}; TileId centerTile(0, input[0].toInt(&canParse[0]), input[1].toInt(&canParse[1]), QFileInfo(input[2]).baseName().toInt(&canParse[2])); if (!canParse[0] || !canParse[1] || !canParse[2]) { qWarning() << "Tile" << input << "does not consist of digits in the format z/x/y.format"; parser.showHelp(); return 1; } TileQueue tileQueue; QSet dynamicTiles; tileQueue.read(dynamicTiles); if (dynamicTiles.contains(centerTile)) { return 0; } QString const extension = QFileInfo(input[2]).completeSuffix(); QString const mbtile = parser.value("mbtile"); QSharedPointer mbtileWriter = QSharedPointer(new MbTileWriter(mbtile, extension)); mbtileWriter->setReportProgress(false); mbtileWriter->setCommitInterval(500); MarbleModel model; ParsingRunnerManager manager(model.pluginManager()); QString const cacheDirectory = parser.value("cache-directory"); QDir().mkpath(cacheDirectory); if (!QFileInfo(cacheDirectory).isWritable()) { qWarning() << "Cannot write to cache directory" << cacheDirectory; parser.showHelp(1); } TileDirectory mapTiles(TileDirectory::OpenStreetMap, cacheDirectory, manager, extension, centerTile.zoomLevel()); TileDirectory landTiles(TileDirectory::Landmass, cacheDirectory, manager, extension, centerTile.zoomLevel()); int const offset = 3; int const N = pow(2,centerTile.zoomLevel()); QRect boundaries = QRect(0, 0, N-1, N-1) & QRect(QPoint(centerTile.x()-offset, centerTile.y()-offset), QPoint(centerTile.x()+offset, centerTile.y()+offset)); int count = 0; int const total = boundaries.width() * boundaries.height(); bool const printProgress = parser.isSet("verbose"); for (int x=boundaries.left(); x<=boundaries.right(); ++x) { for (int y=boundaries.top(); y<=boundaries.bottom(); ++y) { auto const tileId = TileId (0, centerTile.zoomLevel(), x, y); ++count; if (mbtileWriter->hasTile(x, y, tileId.zoomLevel())) { continue; } typedef QSharedPointer GeoDocPtr; GeoDocPtr tile1 = GeoDocPtr(mapTiles.clip(tileId.zoomLevel(), tileId.x(), tileId.y())); TagsFilter::removeAnnotationTags(tile1.data()); if (tileId.zoomLevel() < 17) { WayConcatenator concatenator(tile1.data()); } NodeReducer nodeReducer(tile1.data(), tileId); GeoDocPtr tile2 = GeoDocPtr(landTiles.clip(tileId.zoomLevel(), tileId.x(), tileId.y())); GeoDocPtr combined = GeoDocPtr(mergeDocuments(tile1.data(), tile2.data())); QBuffer buffer; buffer.open(QBuffer::ReadWrite); if (GeoDataDocumentWriter::write(&buffer, *combined, extension)) { buffer.seek(0); mbtileWriter->addTile(&buffer, tileId.x(), tileId.y(), tileId.zoomLevel()); } else { qWarning() << "Could not write the tile " << combined->name(); } dynamicTiles << tileId; if (printProgress) { TileDirectory::printProgress(qreal(count) / total); std::cout << " Tile " << count << "/" << total << " ("; std::cout << combined->name().toStdString() << ")."; std::cout << std::string(20, ' ') << '\r'; std::cout.flush(); } } } tileQueue.write(dynamicTiles); if (printProgress) { TileDirectory::printProgress(1.0); std::cout << "Vector OSM tiles complete after " << timer.elapsed() << " ms." << std::string(30, ' ') << std::endl; } return 0; } diff --git a/tools/vectorosm-tilecreator/vectorosm-tilecreator.cpp b/tools/vectorosm-tilecreator/vectorosm-tilecreator.cpp index 3e74ceca5..4d790ada8 100644 --- a/tools/vectorosm-tilecreator/vectorosm-tilecreator.cpp +++ b/tools/vectorosm-tilecreator/vectorosm-tilecreator.cpp @@ -1,348 +1,348 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 David Kolozsvari // Copyright 2016 Dennis Nienhüser // -#include "GeoDataTypes.h" #include "GeoDataDocumentWriter.h" #include "MarbleModel.h" #include "ParsingRunnerManager.h" #include "GeoDataGeometry.h" #include "GeoDataPlacemark.h" +#include "GeoDataPolygon.h" #include "GeoDataLatLonAltBox.h" #include "TileId.h" #include "MarbleDirs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "VectorClipper.h" #include "NodeReducer.h" #include "WayConcatenator.h" #include "TileIterator.h" #include "TileDirectory.h" #include "MbTileWriter.h" #include "SpellChecker.h" #include using namespace Marble; GeoDataDocument* mergeDocuments(GeoDataDocument* map1, GeoDataDocument* map2) { GeoDataDocument* mergedMap = new GeoDataDocument(*map1); OsmPlacemarkData marbleLand; marbleLand.addTag("marble_land","landmass"); for (auto placemark: map2->placemarkList()) { GeoDataPlacemark* land = new GeoDataPlacemark(*placemark); - if(land->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) { + if (geodata_cast(land->geometry())) { land->setOsmData(marbleLand); } mergedMap->append(land); } return mergedMap; } QString tileFileName(const QCommandLineParser &parser, int x, int y, int zoomLevel) { QString const extension = parser.value("extension"); QString const output = parser.isSet("development") ? QString("%1/maps/earth/vectorosm-dev").arg(MarbleDirs::localPath()) : parser.value("output"); QString const outputDir = QString("%1/%2/%3").arg(output).arg(zoomLevel).arg(x); QString const outputFile = QString("%1/%2.%3").arg(outputDir).arg(y).arg(extension); return outputFile; } void writeBoundaryTile(GeoDataDocument* tile, const QString ®ion, const QCommandLineParser &parser, int x, int y, int zoomLevel) { QString const extension = parser.value("extension"); QString const outputDir = QString("%1/boundaries/%2/%3/%4").arg(parser.value("cache-directory")).arg(region).arg(zoomLevel).arg(x); QString const outputFile = QString("%1/%2.%3").arg(outputDir).arg(y).arg(extension); QDir().mkpath(outputDir); GeoDataDocumentWriter::write(outputFile, *tile); } QSharedPointer mergeBoundaryTiles(const QSharedPointer &background, ParsingRunnerManager &manager, const QCommandLineParser &parser, int x, int y, int zoomLevel) { GeoDataDocument* mergedMap = new GeoDataDocument; OsmPlacemarkData marbleLand; marbleLand.addTag("marble_land","landmass"); for (auto placemark: background->placemarkList()) { GeoDataPlacemark* land = new GeoDataPlacemark(*placemark); - if(land->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType) { + if (geodata_cast(land->geometry())) { land->setOsmData(marbleLand); } mergedMap->append(land); } QString const extension = parser.value("extension"); QString const boundaryDir = QString("%1/boundaries").arg(parser.value("cache-directory")); for(auto const &dir: QDir(boundaryDir).entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { QString const file = QString("%1/%2/%3/%4/%5.%6").arg(boundaryDir).arg(dir).arg(zoomLevel).arg(x).arg(y).arg(extension); if (QFileInfo(file).exists()) { auto tile = TileDirectory::open(file, manager); if (tile) { for (auto placemark: tile->placemarkList()) { mergedMap->append(placemark->clone()); } } } } return QSharedPointer(mergedMap); } bool writeTile(GeoDataDocument* tile, const QString &outputFile) { QDir().mkpath(QFileInfo(outputFile).path()); if (!GeoDataDocumentWriter::write(outputFile, *tile)) { qWarning() << "Could not write the file " << outputFile; return false; } return true; } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QCoreApplication::setApplicationName("marble-vectorosm-tilecreator"); QCoreApplication::setApplicationVersion("0.1"); QCommandLineParser parser; parser.setApplicationDescription("A tool for Marble, which is used to reduce the details of osm maps."); parser.addHelpOption(); parser.addVersionOption(); parser.addPositionalArgument("input", "The input .osm or .shp file."); parser.addOptions({ {{"t", "osmconvert"}, "Tile data using osmconvert."}, {"conflict-resolution", "How to deal with existing tiles: overwrite, skip or merge", "mode", "overwrite"}, {{"c", "cache-directory"}, "Directory for temporary data.", "cache", "cache"}, {{"m", "mbtile"}, "Store tiles at level 15 onwards in a mbtile database.", "mbtile"}, {{"s", "spellcheck"}, "Use this geonames.org cities file for spell-checking city names", "spellcheck"}, {"verbose", "Increase amount of shell output information"}, {"boundaries", "Write boundary tiles (implied by conflict-resolution=merge)"}, {{"d", "development"}, "Use local development vector osm map theme as output storage"}, {{"z", "zoom-level"}, "Zoom level according to which OSM information has to be processed.", "levels", "11,13,15,17"}, {{"o", "output"}, "Output file or directory", "output", QString("%1/maps/earth/vectorosm").arg(MarbleDirs::localPath())}, {{"e", "extension"}, "Output file type: o5m (default), osm or kml", "file extension", "o5m"} }); // Process the actual command line arguments given by the user parser.process(app); const QStringList args = parser.positionalArguments(); if (args.isEmpty()) { parser.showHelp(); return 0; } // input is args.at(0), output is args.at(1) QString const extension = parser.value("extension"); QString inputFileName = args.at(0); auto const levels = parser.value("zoom-level").split(','); QVector zoomLevels; int maxZoomLevel = 0; for(auto const &level: levels) { int const zoomLevel = level.toInt(); maxZoomLevel = qMax(zoomLevel, maxZoomLevel); zoomLevels << zoomLevel; } if (zoomLevels.isEmpty()) { parser.showHelp(1); return 1; } bool const overwriteTiles = parser.value("conflict-resolution") == "overwrite"; bool const mergeTiles = parser.value("conflict-resolution") == "merge"; bool const writeBoundaries = mergeTiles || parser.isSet("boundaries"); QSharedPointer mbtileWriter; if (parser.isSet("mbtile")) { QString const mbtile = parser.value("mbtile"); mbtileWriter = QSharedPointer(new MbTileWriter(mbtile, extension)); mbtileWriter->setReportProgress(false); mbtileWriter->setCommitInterval(500); } MarbleModel model; ParsingRunnerManager manager(model.pluginManager()); QString const cacheDirectory = parser.value("cache-directory"); QDir().mkpath(cacheDirectory); if (!QFileInfo(cacheDirectory).isWritable()) { qWarning() << "Cannot write to cache directory" << cacheDirectory; parser.showHelp(1); } if (*zoomLevels.cbegin() <= 9) { auto map = TileDirectory::open(inputFileName, manager); VectorClipper processor(map.data(), maxZoomLevel); GeoDataLatLonBox world(85.0, -85.0, 180.0, -180.0, GeoDataCoordinates::Degree); if (parser.isSet("spellcheck")) { SpellChecker spellChecker(parser.value("spellcheck")); spellChecker.setVerbose(parser.isSet("verbose")); spellChecker.correctPlaceLabels(map.data()->placemarkList()); } for(auto zoomLevel: zoomLevels) { TileIterator iter(world, zoomLevel); qint64 count = 0; qint64 const total = iter.total(); for(auto const &tileId: iter) { ++count; QString const filename = tileFileName(parser, tileId.x(), tileId.y(), zoomLevel); if (!overwriteTiles && QFileInfo(filename).exists()) { continue; } GeoDataDocument* tile = processor.clipTo(zoomLevel, tileId.x(), tileId.y()); if (tile->size() > 0) { NodeReducer nodeReducer(tile, TileId(0, zoomLevel, tileId.x(), tileId.y())); if (!writeTile(tile, filename)) { return 4; } TileDirectory::printProgress(count / double(total)); std::cout << " Tile " << count << "/" << total << " (" << tile->name().toStdString() << ") done."; double const reduction = nodeReducer.removedNodes() / qMax(1.0, double(nodeReducer.remainingNodes() + nodeReducer.removedNodes())); std::cout << " Node reduction: " << qRound(reduction * 100.0) << "%"; } else { TileDirectory::printProgress(count / double(total)); std::cout << " Skipping empty tile " << count << "/" << total << " (" << tile->name().toStdString() << ")."; } std::cout << std::string(20, ' ') << '\r'; std::cout.flush(); delete tile; } } } else { QString const region = QFileInfo(inputFileName).fileName(); QString const regionDir = QString("%1/%2").arg(cacheDirectory).arg(QFileInfo(inputFileName).baseName()); TileDirectory mapTiles(TileDirectory::OpenStreetMap, regionDir, manager, extension, maxZoomLevel); mapTiles.setInputFile(inputFileName); mapTiles.createTiles(); auto const boundingBox = mapTiles.boundingBox(); TileDirectory loader(TileDirectory::Landmass, cacheDirectory, manager, extension, maxZoomLevel); loader.setBoundingBox(boundingBox); loader.createTiles(); typedef QMap > Tiles; Tiles tiles; qint64 total = 0; QSet boundaryTiles; for(auto zoomLevel: zoomLevels) { TileIterator iter(mapTiles.boundingBox(), zoomLevel); total += iter.total(); for(auto const &tileId: iter) { auto const tile = TileId(0, zoomLevel, tileId.x(), tileId.y()); int const innerNodes = mapTiles.innerNodes(tile); if (innerNodes > 0) { auto const mapTile = mapTiles.tileFor(zoomLevel, tileId.x(), tileId.y()); auto const name = QString("%1/%2/%3").arg(mapTile.zoomLevel()).arg(mapTile.x()).arg(mapTile.y()); tiles[name] << tile; if (innerNodes < 4) { boundaryTiles << name; } } else { --total; } } } qint64 count = 0; for (auto iter = tiles.begin(), end = tiles.end(); iter != end; ++iter) { for(auto const &tileId: iter.value()) { ++count; int const zoomLevel = tileId.zoomLevel(); QString const filename = tileFileName(parser, tileId.x(), tileId.y(), zoomLevel); if (!overwriteTiles) { if (zoomLevel > 13 && mbtileWriter && mbtileWriter->hasTile(tileId.x(), tileId.y(), zoomLevel)) { continue; } else if (QFileInfo(filename).exists()) { continue; } } typedef QSharedPointer GeoDocPtr; GeoDocPtr tile2 = GeoDocPtr(loader.clip(zoomLevel, tileId.x(), tileId.y())); if (tile2->size() > 0) { GeoDocPtr tile1 = GeoDocPtr(mapTiles.clip(zoomLevel, tileId.x(), tileId.y())); TagsFilter::removeAnnotationTags(tile1.data()); int originalWays = 0; int mergedWays = 0; if (zoomLevel < 17) { WayConcatenator concatenator(tile1.data()); originalWays = concatenator.originalWays(); mergedWays = concatenator.mergedWays(); } NodeReducer nodeReducer(tile1.data(), tileId); if (tile1->size() > 0 && tile2->size() > 0) { GeoDocPtr combined = GeoDocPtr(mergeDocuments(tile1.data(), tile2.data())); if (writeBoundaries && boundaryTiles.contains(iter.key())) { writeBoundaryTile(tile1.data(), region, parser, tileId.x(), tileId.y(), zoomLevel); if (mergeTiles) { combined = mergeBoundaryTiles(tile2, manager, parser, tileId.x(), tileId.y(), zoomLevel); } } if (zoomLevel > 13 && mbtileWriter) { QBuffer buffer; buffer.open(QBuffer::ReadWrite); if (GeoDataDocumentWriter::write(&buffer, *combined, extension)) { buffer.seek(0); mbtileWriter->addTile(&buffer, tileId.x(), tileId.y(), zoomLevel); } else { qWarning() << "Could not write the tile " << combined->name(); } } else { if (!writeTile(combined.data(), filename)) { return 4; } } TileDirectory::printProgress(count / double(total)); std::cout << " Tile " << count << "/" << total << " ("; std::cout << combined->name().toStdString() << ")."; double const reduction = nodeReducer.removedNodes() / qMax(1.0, double(nodeReducer.remainingNodes() + nodeReducer.removedNodes())); std::cout << " Node reduction: " << qRound(reduction * 100.0) << "%"; if (originalWays > 0) { std::cout << " , " << originalWays << " ways merged to " << mergedWays; } } else { TileDirectory::printProgress(count / double(total)); std::cout << " Skipping empty tile " << count << "/" << total << " (" << tile1->name().toStdString() << ")."; } } else { TileDirectory::printProgress(count / double(total)); std::cout << " Skipping sea tile " << count << "/" << total << " (" << tile2->name().toStdString() << ")."; } std::cout << std::string(20, ' ') << '\r'; std::cout.flush(); } } TileDirectory::printProgress(1.0); std::cout << " Vector OSM tiles complete." << std::string(30, ' ') << std::endl; } return 0; }