diff --git a/src/lib/marble/routing/RoutingModel.cpp b/src/lib/marble/routing/RoutingModel.cpp index 50282e5e1..3e3a93a7b 100644 --- a/src/lib/marble/routing/RoutingModel.cpp +++ b/src/lib/marble/routing/RoutingModel.cpp @@ -1,319 +1,319 @@ // // 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 "RoutingModel.h" #include "Planet.h" #include "PlanetFactory.h" #include "MarbleMath.h" #include "Route.h" #include "RouteRequest.h" #include "PositionTracking.h" #include "MarbleModel.h" #include "MarbleGlobal.h" #include "GeoDataAccuracy.h" #include namespace Marble { class RoutingModelPrivate { public: enum RouteDeviation { Unknown, OnRoute, OffRoute }; - explicit RoutingModelPrivate( RouteRequest* request ); + explicit RoutingModelPrivate(PositionTracking *positionTracking, RouteRequest *request); Route m_route; - PositionTracking* m_positionTracking; + PositionTracking *const m_positionTracking; RouteRequest* const m_request; QHash m_roleNames; RouteDeviation m_deviation; void updateViaPoints( const GeoDataCoordinates &position ); }; -RoutingModelPrivate::RoutingModelPrivate(RouteRequest *request) : - m_positionTracking(0), +RoutingModelPrivate::RoutingModelPrivate(PositionTracking *positionTracking, RouteRequest *request) : + m_positionTracking(positionTracking), m_request(request), m_deviation(Unknown) { // nothing to do } void RoutingModelPrivate::updateViaPoints( const GeoDataCoordinates &position ) { // Mark via points visited after approaching them in a range of 500m or less qreal const threshold = 500 / EARTH_RADIUS; for( int i=0; isize(); ++i ) { if ( !m_request->visited( i ) ) { if ( distanceSphere( position, m_request->at( i ) ) < threshold ) { m_request->setVisited( i, true ); } } } } RoutingModel::RoutingModel( RouteRequest* request, MarbleModel *model, QObject *parent ) : - QAbstractListModel( parent ), d( new RoutingModelPrivate( request ) ) + QAbstractListModel(parent), + d(new RoutingModelPrivate(model->positionTracking(), request)) { - d->m_positionTracking = model->positionTracking(); QObject::connect( d->m_positionTracking, SIGNAL(gpsLocation(GeoDataCoordinates,qreal)), this, SLOT(updatePosition(GeoDataCoordinates,qreal)) ); QHash roles; roles.insert( Qt::DisplayRole, "display" ); roles.insert( RoutingModel::TurnTypeIconRole, "turnTypeIcon" ); roles.insert( RoutingModel::LongitudeRole, "longitude" ); roles.insert( RoutingModel::LatitudeRole, "latitude" ); d->m_roleNames = roles; } RoutingModel::~RoutingModel() { delete d; } int RoutingModel::rowCount ( const QModelIndex &parent ) const { return parent.isValid() ? 0 : d->m_route.turnPoints().size(); } QVariant RoutingModel::headerData ( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0 ) { return QString( "Instruction" ); } return QAbstractListModel::headerData( section, orientation, role ); } QVariant RoutingModel::data ( const QModelIndex & index, int role ) const { if ( !index.isValid() ) { return QVariant(); } if ( index.row() < d->m_route.turnPoints().size() && index.column() == 0 ) { const RouteSegment &segment = d->m_route.at( index.row() ); switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return segment.maneuver().instructionText(); break; case Qt::DecorationRole: { bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; if ( segment.maneuver().hasWaypoint() ) { int const size = smallScreen ? 64 : 32; return d->m_request->pixmap( segment.maneuver().waypointIndex(), size, size/4 ); } else { QPixmap const pixmap = segment.maneuver().directionPixmap(); return smallScreen ? pixmap : pixmap.scaled( 32, 32 ); } } break; case Qt::SizeHintRole: { bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; int const size = smallScreen ? 64 : 32; return QSize( size, size ); } break; case RoutingModel::CoordinateRole: return QVariant::fromValue( segment.maneuver().position() ); break; case RoutingModel::LongitudeRole: return QVariant(segment.maneuver().position().longitude(GeoDataCoordinates::Degree)); break; case RoutingModel::LatitudeRole: return QVariant(segment.maneuver().position().latitude(GeoDataCoordinates::Degree)); break; case RoutingModel::TurnTypeIconRole: return segment.maneuver().directionPixmap(); break; default: return QVariant(); } } return QVariant(); } QHash RoutingModel::roleNames() const { return d->m_roleNames; } void RoutingModel::setRoute( const Route &route ) { d->m_route = route; d->m_deviation = RoutingModelPrivate::Unknown; beginResetModel(); endResetModel(); emit currentRouteChanged(); } void RoutingModel::exportGpx( QIODevice *device ) const { QString content = QLatin1String("\n" "\n" "\n \n " "Marble Virtual Globe\n \n\n" " \n Route\n"); bool hasAltitude = false; for ( int i=0; !hasAltitude && im_route.size(); ++i ) { hasAltitude = d->m_route.at( i ).maneuver().position().altitude() != 0.0; } for ( int i=0; im_route.size(); ++i ) { const Maneuver &maneuver = d->m_route.at( i ).maneuver(); qreal lon = maneuver.position().longitude( GeoDataCoordinates::Degree ); qreal lat = maneuver.position().latitude( GeoDataCoordinates::Degree ); QString const text = maneuver.instructionText(); content += QString( " \n" ).arg( lat, 0, 'f', 7 ).arg( lon, 0, 'f', 7 ); content += QString( " %1\n").arg( text ); if ( hasAltitude ) { content += QString( " %1\n" ).arg( maneuver.position().altitude(), 0, 'f', 2 ); } content += QString( " \n" ); } content += QLatin1String(" \n" "\n Route\n \n"); GeoDataLineString points = d->m_route.path(); hasAltitude = false; for ( int i=0; !hasAltitude && i\n" ).arg( lat, 0, 'f', 7 ).arg( lon, 0, 'f', 7 ); if ( hasAltitude ) { content += QString( " %1\n" ).arg( point.altitude(), 0, 'f', 2 ); } content += QString( " \n" ); } content += QLatin1String(" \n \n" "\n"); device->write( content.toUtf8() ); } void RoutingModel::clear() { d->m_route = Route(); beginResetModel(); endResetModel(); emit currentRouteChanged(); } int RoutingModel::rightNeighbor( const GeoDataCoordinates &position, RouteRequest const *const route ) const { Q_ASSERT( route && "Must not pass a null route "); // Quick result for trivial cases if ( route->size() < 3 ) { return route->size() - 1; } // Generate an ordered list of all waypoints GeoDataLineString points = d->m_route.path(); QMap mapping; // Force first mapping point to match the route start mapping[0] = 0; // Calculate the mapping between waypoints and via points // Need two for loops to avoid getting stuck in local minima for ( int j=1; jsize()-1; ++j ) { qreal minDistance = -1.0; for ( int i=mapping[j-1]; iat(j) ); if (minDistance < 0.0 || distance < minDistance ) { mapping[j] = i; minDistance = distance; } } } // Determine waypoint with minimum distance to the provided position qreal minWaypointDistance = -1.0; int waypoint=0; for ( int i=0; isize()-1] = points.size()-1; // Determine neighbor based on the mapping QMap::const_iterator iter = mapping.constBegin(); for ( ; iter != mapping.constEnd(); ++iter ) { if ( iter.value() > waypoint ) { int index = iter.key(); Q_ASSERT( index >= 0 && index <= route->size() ); return index; } } return route->size()-1; } void RoutingModel::updatePosition( GeoDataCoordinates location, qreal speed ) { d->m_route.setPosition( location ); d->updateViaPoints( location ); const qreal planetRadius = PlanetFactory::construct("earth").radius(); qreal distance = planetRadius * distanceSphere( location, d->m_route.positionOnRoute() ); emit positionChanged(); qreal deviation = 0.0; if ( d->m_positionTracking && d->m_positionTracking->accuracy().vertical > 0.0 ) { deviation = qMax( d->m_positionTracking->accuracy().vertical, d->m_positionTracking->accuracy().horizontal ); } qreal const threshold = deviation + qBound(10.0, speed*10.0, 150.0); RoutingModelPrivate::RouteDeviation const deviated = distance < threshold ? RoutingModelPrivate::OnRoute : RoutingModelPrivate::OffRoute; if ( d->m_deviation != deviated ) { d->m_deviation = deviated; emit deviatedFromRoute( deviated == RoutingModelPrivate::OffRoute ); } } bool RoutingModel::deviatedFromRoute() const { return d->m_deviation == RoutingModelPrivate::OffRoute; } const Route & RoutingModel::route() const { return d->m_route; } } // namespace Marble #include "moc_RoutingModel.cpp"