@ -1,12 +1,11 @@
# include <cmath>
# include <QDebug>
# include <QJsonDocument>
# include <QJsonObject>
# include "selfdrive/common/util.h"
# include "selfdrive/common/swaglog.h"
# include "selfdrive/common/params.h"
# include "selfdrive/ui/ui.h"
# include "selfdrive/ui/qt/util.h"
# include "selfdrive/ui/qt/maps/map_helpers.h"
# include "selfdrive/ui/qt/maps/map.h"
@ -52,6 +51,12 @@ MapWindow::MapWindow(const QMapboxGLSettings &settings) : m_settings(settings) {
}
connect ( routing_manager , SIGNAL ( finished ( QGeoRouteReply * ) ) , this , SLOT ( routeCalculated ( QGeoRouteReply * ) ) ) ;
auto last_gps_position = coordinate_from_param ( " LastGPSPosition " ) ;
if ( last_gps_position ) {
last_position = * last_gps_position ;
}
grabGesture ( Qt : : GestureType : : PinchGesture ) ;
}
@ -99,58 +104,20 @@ void MapWindow::initLayers() {
}
void MapWindow : : timerUpdate ( ) {
if ( ! isVisible ( ) ) return ;
initLayers ( ) ;
sm - > update ( 0 ) ;
if ( sm - > updated ( " liveLocationKalman " ) ) {
auto location = ( * sm ) [ " liveLocationKalman " ] . getLiveLocationKalman ( ) ;
auto pos = location . getPositionGeodetic ( ) ;
auto orientation = location . getOrientationNED ( ) ;
float velocity = location . getVelocityCalibrated ( ) . getValue ( ) [ 0 ] ;
static FirstOrderFilter velocity_filter ( velocity , 10 , 0.1 ) ;
auto coordinate = QMapbox : : Coordinate ( pos . getValue ( ) [ 0 ] , pos . getValue ( ) [ 1 ] ) ;
if ( location . getStatus ( ) = = cereal : : LiveLocationKalman : : Status : : VALID ) {
gps_ok = location . getGpsOK ( ) ;
// Update map location, orientation and zoom on valid localizer output
if ( location . getStatus ( ) = = cereal : : LiveLocationKalman : : Status : : VALID ) {
auto pos = location . getPositionGeodetic ( ) ;
float velocity = location . getVelocityCalibrated ( ) . getValue ( ) [ 0 ] ;
auto orientation = location . getOrientationNED ( ) ;
auto coordinate = QMapbox : : Coordinate ( pos . getValue ( ) [ 0 ] , pos . getValue ( ) [ 1 ] ) ;
last_position = coordinate ;
gps_ok = location . getGpsOK ( ) ;
if ( sm - > frame % 10 = = 0 & & shouldRecompute ( ) ) {
calculateRoute ( nav_destination ) ;
}
if ( segment . isValid ( ) ) {
auto cur_maneuver = segment . maneuver ( ) ;
auto attrs = cur_maneuver . extendedAttributes ( ) ;
if ( cur_maneuver . isValid ( ) & & attrs . contains ( " mapbox.banner_instructions " ) ) {
auto banner = attrs [ " mapbox.banner_instructions " ] . toList ( ) ;
if ( banner . size ( ) ) {
// TOOD: Only show when traveled distanceAlongGeometry since the start
map_instructions - > setVisible ( true ) ;
emit instructionsChanged ( banner [ 0 ] . toMap ( ) ) ;
}
}
auto next_segment = segment . nextRouteSegment ( ) ;
if ( next_segment . isValid ( ) ) {
auto next_maneuver = next_segment . maneuver ( ) ;
if ( next_maneuver . isValid ( ) ) {
float next_maneuver_distance = next_maneuver . position ( ) . distanceTo ( to_QGeoCoordinate ( last_position ) ) ;
emit distanceChanged ( next_maneuver_distance ) ;
m_map - > setPitch ( MAX_PITCH ) ; // TODO: smooth pitching based on maneuver distance
if ( next_maneuver_distance < REROUTE_DISTANCE & & next_maneuver_distance > last_maneuver_distance ) {
segment = next_segment ;
}
last_maneuver_distance = next_maneuver_distance ;
}
}
}
if ( pan_counter = = 0 ) {
m_map - > setCoordinate ( coordinate ) ;
@ -160,6 +127,7 @@ void MapWindow::timerUpdate() {
}
if ( zoom_counter = = 0 ) {
static FirstOrderFilter velocity_filter ( velocity , 10 , 0.1 ) ;
m_map - > setZoom ( util : : map_val < float > ( velocity_filter . update ( velocity ) , 0 , 30 , MAX_ZOOM , MIN_ZOOM ) ) ;
} else {
zoom_counter - - ;
@ -184,8 +152,66 @@ void MapWindow::timerUpdate() {
m_map - > updateSource ( " modelPathSource " , modelPathSource ) ;
}
}
update ( ) ;
// Recompute route if needed
if ( sm - > frame % 10 = = 0 ) {
if ( recompute_countdown = = 0 & & shouldRecompute ( ) ) {
recompute_countdown = std : : pow ( 2 , recompute_backoff ) ;
recompute_backoff = std : : min ( 7 , recompute_backoff + 1 ) ;
calculateRoute ( nav_destination ) ;
} else {
recompute_countdown = std : : max ( 0 , recompute_countdown - 1 ) ;
}
}
// Show route instructions
if ( segment . isValid ( ) ) {
auto cur_maneuver = segment . maneuver ( ) ;
auto attrs = cur_maneuver . extendedAttributes ( ) ;
if ( cur_maneuver . isValid ( ) & & attrs . contains ( " mapbox.banner_instructions " ) ) {
auto banner = attrs [ " mapbox.banner_instructions " ] . toList ( ) ;
if ( banner . size ( ) ) {
// TOOD: Only show when traveled distanceAlongGeometry since the start
map_instructions - > setVisible ( true ) ;
emit instructionsChanged ( banner [ 0 ] . toMap ( ) ) ;
}
}
auto next_segment = segment . nextRouteSegment ( ) ;
if ( next_segment . isValid ( ) ) {
auto next_maneuver = next_segment . maneuver ( ) ;
if ( next_maneuver . isValid ( ) ) {
float next_maneuver_distance = next_maneuver . position ( ) . distanceTo ( to_QGeoCoordinate ( last_position ) ) ;
emit distanceChanged ( next_maneuver_distance ) ;
m_map - > setPitch ( MAX_PITCH ) ; // TODO: smooth pitching based on maneuver distance
// Switch to next route segment
if ( next_maneuver_distance < REROUTE_DISTANCE & & next_maneuver_distance > last_maneuver_distance ) {
segment = next_segment ;
recompute_backoff = std : : max ( 0 , recompute_backoff - 1 ) ;
recompute_countdown = 0 ;
}
last_maneuver_distance = next_maneuver_distance ;
}
} else {
Params ( ) . remove ( " NavDestination " ) ;
// Clear route if driving away from destination
float d = segment . maneuver ( ) . position ( ) . distanceTo ( to_QGeoCoordinate ( last_position ) ) ;
if ( d > REROUTE_DISTANCE ) {
clearRoute ( ) ;
}
}
}
}
update ( ) ;
if ( ! segment . isValid ( ) ) {
map_instructions - > setVisible ( false ) ;
}
@ -210,6 +236,8 @@ void MapWindow::initializeGL() {
}
void MapWindow : : paintGL ( ) {
if ( ! isVisible ( ) ) return ;
m_map - > resize ( size ( ) / MAP_SCALE ) ;
m_map - > setFramebufferObject ( defaultFramebufferObject ( ) , size ( ) ) ;
m_map - > render ( ) ;
@ -218,6 +246,7 @@ void MapWindow::paintGL() {
void MapWindow : : calculateRoute ( QMapbox : : Coordinate destination ) {
QGeoRouteRequest request ( to_QGeoCoordinate ( last_position ) , to_QGeoCoordinate ( destination ) ) ;
request . setFeatureWeight ( QGeoRouteRequest : : TrafficFeature , QGeoRouteRequest : : AvoidFeatureWeight ) ;
routing_manager - > calculateRoute ( request ) ;
}
@ -233,29 +262,32 @@ void MapWindow::routeCalculated(QGeoRouteReply *reply) {
navSource [ " type " ] = " geojson " ;
navSource [ " data " ] = QVariant : : fromValue < QMapbox : : Feature > ( feature ) ;
m_map - > updateSource ( " navSource " , navSource ) ;
has_route = true ;
m_map - > setLayoutProperty ( " navLayer " , " visibility " , " visible " ) ;
}
reply - > deleteLater ( ) ;
}
void MapWindow : : clearRoute ( ) {
segment = QGeoRouteSegment ( ) ; // Clear route
m_map - > setLayoutProperty ( " navLayer " , " visibility " , " none " ) ;
m_map - > setPitch ( MIN_PITCH ) ;
}
bool MapWindow : : shouldRecompute ( ) {
if ( ! gps_ok ) return false ; // Don't recompute when gps drifts in tunnels
QString nav_destination_json = QString : : fromStdString ( Params ( ) . get ( " NavDestination " ) ) ;
if ( nav_destination_json . isEmpty ( ) ) return false ;
bool MapWindow : : shouldRecompute ( ) {
auto new_destination = coordinate_from_param ( " NavDestination " ) ;
if ( ! new_destination ) {
clearRoute ( ) ;
return false ;
}
QJsonDocument doc = QJsonDocument : : fromJson ( nav_destination_json . toUtf8 ( ) ) ;
if ( doc . isNull ( ) ) return false ;
if ( ! gps_ok & & segment . isValid ( ) ) return false ; // Don't recompute when gps drifts in tunnels
QJsonObject json = doc . object ( ) ;
if ( json [ " latitude " ] . isDouble ( ) & & json [ " longitude " ] . isDouble ( ) ) {
QMapbox : : Coordinate new_destination ( json [ " latitude " ] . toDouble ( ) , json [ " longitude " ] . toDouble ( ) ) ;
if ( new_destination ! = nav_destination ) {
nav_destination = new_destination ;
return true ;
}
if ( * new_destination ! = nav_destination ) {
nav_destination = * new_destination ;
setVisible ( true ) ; // Show map on destination set/change
return true ;
}
if ( ! segment . isValid ( ) ) {
@ -385,16 +417,27 @@ MapInstructions::MapInstructions(QWidget * parent) : QWidget(parent){
void MapInstructions : : updateDistance ( float d ) {
QString distance_str ;
float miles = d * METER_2_MILE ;
float feet = d * METER_2_FOOT ;
if ( feet > 500 ) {
distance_str . setNum ( miles , ' f ' , 1 ) ;
distance_str + = " miles " ;
if ( QUIState : : ui_state . scene . is_metric ) {
if ( d > 500 ) {
distance_str . setNum ( d / 1000 , ' f ' , 1 ) ;
distance_str + = " km " ;
} else {
distance_str . setNum ( 50 * int ( d / 50 ) ) ;
distance_str + = " m " ;
}
} else {
distance_str . setNum ( 50 * int ( feet / 50 ) ) ;
distance_str + = " feet " ;
float miles = d * METER_2_MILE ;
float feet = d * METER_2_FOOT ;
if ( feet > 500 ) {
distance_str . setNum ( miles , ' f ' , 1 ) ;
distance_str + = " miles " ;
} else {
distance_str . setNum ( 50 * int ( feet / 50 ) ) ;
distance_str + = " feet " ;
}
}
distance - > setText ( distance_str ) ;
}