// // This file is part of the Marble Desktop 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 <tackat@kde.org> // Copyright 2007 Inge Wallin <ingwa@kde.org> // #include "PlacemarkManager.h" #include <QtCore/QBuffer> #include <QtCore/QByteArray> #include <QtCore/QDataStream> #include <QtCore/QDateTime> #include <QtCore/QDir> #include <QtCore/QFileInfo> #include "MarbleDebug.h" #include "FileManager.h" #include "KmlFileViewItem.h" #include "FileViewModel.h" #include "MarbleDirs.h" #include "MarblePlacemarkModel.h" #include "MarbleDataFacade.h" #include "GeoDataDocument.h" #include "GeoDataParser.h" #include "GeoDataPlacemark.h" using namespace Marble; namespace Marble { class PlacemarkManagerPrivate { public: PlacemarkManagerPrivate( ) : m_datafacade( 0 ) { } MarbleDataFacade* m_datafacade; FileManager *m_fileManager; QVector<GeoDataPlacemark> m_placemarkContainer; QVector<int> m_sizeForDocument; }; } PlacemarkManager::PlacemarkManager( QObject *parent ) : QObject( parent ) , d( new PlacemarkManagerPrivate() ) { } PlacemarkManager::~PlacemarkManager() { delete d; } MarblePlacemarkModel* PlacemarkManager::model() const { return d->m_datafacade->placemarkModel(); } void PlacemarkManager::setDataFacade( MarbleDataFacade *facade ) { d->m_datafacade = facade; d->m_datafacade->placemarkModel()->setPlacemarkContainer(&d->m_placemarkContainer); } void PlacemarkManager::setFileManager( FileManager *fileManager ) { d->m_fileManager = fileManager; connect( d->m_fileManager, SIGNAL( fileAdded(int)), this, SLOT(addGeoDataDocument(int)) ); connect( d->m_fileManager, SIGNAL( fileRemoved(int)), this, SLOT(removeGeoDataDocument(int)) ); } void PlacemarkManager::addGeoDataDocument( int index ) { KmlFileViewItem *file = static_cast<KmlFileViewItem*>(d->m_fileManager->at(index)); if (file) { const GeoDataDocument &document = *file->document(); QVector<GeoDataPlacemark> result = recurseContainer(document); if (!result.isEmpty()) { createFilterProperties( result ); int start = d->m_placemarkContainer.size(); d->m_placemarkContainer << result; d->m_sizeForDocument.resize(index+1); d->m_sizeForDocument[index] = result.size(); mDebug() << "PlacemarkManager::addGeoDataDocument:" << document.fileName() << " size " << result.size(); d->m_datafacade->placemarkModel()->addPlacemarks( start, result.size() ); } } } void PlacemarkManager::removeGeoDataDocument( int index ) { KmlFileViewItem *file = static_cast<KmlFileViewItem*>(d->m_fileManager->at(index)); if (file) { const GeoDataDocument &document = *file->document(); int start = 0; for ( int i = 0; i < index; ++i ) { start += d->m_sizeForDocument[i]; } int size = d->m_sizeForDocument[index]; d->m_placemarkContainer.remove(start, size); if (d->m_sizeForDocument.size() > index) d->m_sizeForDocument.remove(index); mDebug() << "PlacemarkManager::removeGeoDataDocument:" << document.fileName() << " size " << size; d->m_datafacade->placemarkModel()->removePlacemarks( document.fileName(), start, size ); } } QVector<GeoDataPlacemark> PlacemarkManager::recurseContainer(GeoDataContainer container) { QVector<GeoDataPlacemark> results; const QVector<GeoDataFeature> features = container.features(); QVector<GeoDataFeature>::const_iterator it = features.constBegin(); QVector<GeoDataFeature>::const_iterator end = features.constEnd(); results += container.placemarks(); for (; it != end; ++it) { if ( GeoDataFolderId == it->featureId() ) { results += recurseContainer(*it); } } return results; } void PlacemarkManager::createFilterProperties( QVector<Marble::GeoDataPlacemark> &container ) { QVector<GeoDataPlacemark>::Iterator i = container.begin(); QVector<GeoDataPlacemark>::Iterator const end = container.end(); for (; i != end; ++i ) { GeoDataPlacemark& placemark = *i; bool hasPopularity = false; // Mountain (H), Volcano (V), Shipwreck (W) if ( placemark.role() == 'H' || placemark.role() == 'V' || placemark.role() == 'W' ) { qreal altitude = placemark.coordinate().altitude(); if ( altitude != 0.0 ) { hasPopularity = true; placemark.setPopularity( (qint64)(altitude * 1000.0) ); placemark.setPopularityIndex( cityPopIdx( qAbs( (qint64)(altitude * 1000.0) ) ) ); } } // Continent (K), Ocean (O), Nation (S) else if ( placemark.role() == 'K' || placemark.role() == 'O' || placemark.role() == 'S' ) { qreal area = placemark.area(); if ( area >= 0.0 ) { hasPopularity = true; // mDebug() << placemark->name() << " " << (qint64)(area); placemark.setPopularity( (qint64)(area * 100) ); placemark.setPopularityIndex( areaPopIdx( area ) ); } } // Pole (P) else if ( placemark.role() == 'P' ) { placemark.setPopularity( 1000000000 ); placemark.setPopularityIndex( 18 ); } // Magnetic Pole (M) else if ( placemark.role() == 'M' ) { placemark.setPopularity( 10000000 ); placemark.setPopularityIndex( 13 ); } // MannedLandingSite (h) else if ( placemark.role() == 'h' ) { placemark.setPopularity( 1000000000 ); placemark.setPopularityIndex( 18 ); } // RoboticRover (r) else if ( placemark.role() == 'r' ) { placemark.setPopularity( 10000000 ); placemark.setPopularityIndex( 16 ); } // UnmannedSoftLandingSite (u) else if ( placemark.role() == 'u' ) { placemark.setPopularity( 1000000 ); placemark.setPopularityIndex( 14 ); } // UnmannedSoftLandingSite (i) else if ( placemark.role() == 'i' ) { placemark.setPopularity( 1000000 ); placemark.setPopularityIndex( 14 ); } // Space Terrain: Craters, Maria, Montes, Valleys, etc. else if ( placemark.role() == 'm' || placemark.role() == 'v' || placemark.role() == 'o' || placemark.role() == 'c' || placemark.role() == 'a' ) { qint64 diameter = placemark.population(); if ( diameter >= 0 ) { hasPopularity = true; placemark.setPopularity( diameter ); if ( placemark.role() == 'c' ) { placemark.setPopularityIndex( spacePopIdx( diameter ) ); if ( placemark.name() == "Tycho" || placemark.name() == "Copernicus" ) { placemark.setPopularityIndex( 17 ); } } else { placemark.setPopularityIndex( spacePopIdx( diameter ) ); } if ( placemark.role() == 'a' && diameter == 0 ) { placemark.setPopularity( 1000000000 ); placemark.setPopularityIndex( 18 ); } } } else { qint64 population = placemark.population(); if ( population >= 0 ) { hasPopularity = true; placemark.setPopularity( population ); placemark.setPopularityIndex( cityPopIdx( population ) ); } } // Then we set the visual category: if ( placemark.role() == 'H' ) placemark.setVisualCategory( GeoDataPlacemark::Mountain ); else if ( placemark.role() == 'V' ) placemark.setVisualCategory( GeoDataPlacemark::Volcano ); else if ( placemark.role() == 'm' ) placemark.setVisualCategory( GeoDataPlacemark::Mons ); else if ( placemark.role() == 'v' ) placemark.setVisualCategory( GeoDataPlacemark::Valley ); else if ( placemark.role() == 'o' ) placemark.setVisualCategory( GeoDataPlacemark::OtherTerrain ); else if ( placemark.role() == 'c' ) placemark.setVisualCategory( GeoDataPlacemark::Crater ); else if ( placemark.role() == 'a' ) placemark.setVisualCategory( GeoDataPlacemark::Mare ); else if ( placemark.role() == 'P' ) placemark.setVisualCategory( GeoDataPlacemark::GeographicPole ); else if ( placemark.role() == 'M' ) placemark.setVisualCategory( GeoDataPlacemark::MagneticPole ); else if ( placemark.role() == 'W' ) placemark.setVisualCategory( GeoDataPlacemark::ShipWreck ); else if ( placemark.role() == 'F' ) placemark.setVisualCategory( GeoDataPlacemark::AirPort ); else if ( placemark.role() == 'A' ) placemark.setVisualCategory( GeoDataPlacemark::Observatory ); else if ( placemark.role() == 'K' ) placemark.setVisualCategory( GeoDataPlacemark::Continent ); else if ( placemark.role() == 'O' ) placemark.setVisualCategory( GeoDataPlacemark::Ocean ); else if ( placemark.role() == 'S' ) placemark.setVisualCategory( GeoDataPlacemark::Nation ); else if ( placemark.role() == 'N' ) placemark.setVisualCategory( ( ( GeoDataPlacemark::GeoDataVisualCategory )( (int)( GeoDataPlacemark::SmallCity ) + ( placemark.popularityIndex() -1 ) / 4 * 4 ) ) ); else if ( placemark.role() == 'R' ) placemark.setVisualCategory( ( ( GeoDataPlacemark::GeoDataVisualCategory )( (int)( GeoDataPlacemark::SmallStateCapital ) + ( placemark.popularityIndex() -1 ) / 4 * 4 ) ) ); else if ( placemark.role() == 'C' || placemark.role() == 'B' ) placemark.setVisualCategory( ( ( GeoDataPlacemark::GeoDataVisualCategory )( (int)( GeoDataPlacemark::SmallNationCapital ) + ( placemark.popularityIndex() -1 ) / 4 * 4 ) ) ); else if ( placemark.role() == ' ' && !hasPopularity && placemark.visualCategory() == GeoDataPlacemark::Unknown ) { placemark.setVisualCategory( GeoDataPlacemark::Unknown ); // default location placemark.setPopularityIndex(0); } else if ( placemark.role() == 'h' ) placemark.setVisualCategory( GeoDataPlacemark::MannedLandingSite ); else if ( placemark.role() == 'r' ) placemark.setVisualCategory( GeoDataPlacemark::RoboticRover ); else if ( placemark.role() == 'u' ) placemark.setVisualCategory( GeoDataPlacemark::UnmannedSoftLandingSite ); else if ( placemark.role() == 'i' ) placemark.setVisualCategory( GeoDataPlacemark::UnmannedHardLandingSite ); if ( placemark.role() == 'W' && placemark.popularityIndex() > 12 ) placemark.setPopularityIndex( 12 ); if ( placemark.role() == 'O' ) placemark.setPopularityIndex( 16 ); if ( placemark.role() == 'K' ) placemark.setPopularityIndex( 19 ); if ( !placemark.isVisible() ) { placemark.setPopularityIndex( -1 ); } // Workaround: Emulate missing "setVisible" serialization by allowing for population // values smaller than -1 which are considered invisible. if ( placemark.population() < -1 ) { placemark.setPopularityIndex( -1 ); } } } int PlacemarkManager::cityPopIdx( qint64 population ) const { int popidx = 15; if ( population < 2500 ) popidx=1; else if ( population < 5000) popidx=2; else if ( population < 7500) popidx=3; else if ( population < 10000) popidx=4; else if ( population < 25000) popidx=5; else if ( population < 50000) popidx=6; else if ( population < 75000) popidx=7; else if ( population < 100000) popidx=8; else if ( population < 250000) popidx=9; else if ( population < 500000) popidx=10; else if ( population < 750000) popidx=11; else if ( population < 1000000) popidx=12; else if ( population < 2500000) popidx=13; else if ( population < 5000000) popidx=14; return popidx; } int PlacemarkManager::spacePopIdx( qint64 population ) const { int popidx = 18; if ( population < 1000 ) popidx=1; else if ( population < 2000) popidx=2; else if ( population < 4000) popidx=3; else if ( population < 6000) popidx=4; else if ( population < 8000) popidx=5; else if ( population < 10000) popidx=6; else if ( population < 20000) popidx=7; else if ( population < 40000 ) popidx=8; else if ( population < 60000) popidx=9; else if ( population < 80000 ) popidx=10; else if ( population < 100000) popidx=11; else if ( population < 200000 ) popidx=13; else if ( population < 400000 ) popidx=15; else if ( population < 600000 ) popidx=17; return popidx; } int PlacemarkManager::areaPopIdx( qreal area ) const { int popidx = 17; if ( area < 200000 ) popidx=11; else if ( area < 400000 ) popidx=12; else if ( area < 1000000 ) popidx=13; else if ( area < 2500000 ) popidx=14; else if ( area < 5000000 ) popidx=15; else if ( area < 10000000 ) popidx=16; return popidx; } #include "PlacemarkManager.moc"