@ -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,29 +104,68 @@ void MapWindow::initLayers() {
}
void MapWindow : : timerUpdate ( ) {
if ( ! isVisible ( ) ) return ;
initLayers ( ) ;
sm - > update ( 0 ) ;
if ( sm - > updated ( " liveLocationKalman " ) ) {
auto location = ( * sm ) [ " liveLocationKalman " ] . getLiveLocationKalman ( ) ;
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 ;
float velocity = location . getVelocityCalibrated ( ) . getValue ( ) [ 0 ] ;
if ( pan_counter = = 0 ) {
m_map - > setCoordinate ( coordinate ) ;
m_map - > setBearing ( RAD2DEG ( orientation . getValue ( ) [ 2 ] ) ) ;
} else {
pan_counter - - ;
}
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 - - ;
}
auto coordinate = QMapbox : : Coordinate ( pos . getValue ( ) [ 0 ] , pos . getValue ( ) [ 1 ] ) ;
// Update current location marker
auto point = coordinate_to_collection ( coordinate ) ;
QMapbox : : Feature feature1 ( QMapbox : : Feature : : PointType , point , { } , { } ) ;
QVariantMap carPosSource ;
carPosSource [ " type " ] = " geojson " ;
carPosSource [ " data " ] = QVariant : : fromValue < QMapbox : : Feature > ( feature1 ) ;
m_map - > updateSource ( " carPosSource " , carPosSource ) ;
if ( location . getStatus ( ) = = cereal : : LiveLocationKalman : : Status : : VALID ) {
last_position = coordinate ;
gps_ok = location . getGpsOK ( ) ;
// Update model path
if ( DRAW_MODEL_PATH ) {
auto model = ( * sm ) [ " modelV2 " ] . getModelV2 ( ) ;
auto path_points = model_to_collection ( location . getCalibratedOrientationECEF ( ) , location . getPositionECEF ( ) , model . getPosition ( ) ) ;
QMapbox : : Feature feature2 ( QMapbox : : Feature : : LineStringType , path_points , { } , { } ) ;
QVariantMap modelPathSource ;
modelPathSource [ " type " ] = " geojson " ;
modelPathSource [ " data " ] = QVariant : : fromValue < QMapbox : : Feature > ( feature2 ) ;
m_map - > updateSource ( " modelPathSource " , modelPathSource ) ;
}
}
if ( sm - > frame % 10 = = 0 & & shouldRecompute ( ) ) {
// 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 ( ) ;
@ -144,48 +188,30 @@ void MapWindow::timerUpdate() {
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 ( ) ;
}
}
if ( pan_counter = = 0 ) {
m_map - > setCoordinate ( coordinate ) ;
m_map - > setBearing ( RAD2DEG ( orientation . getValue ( ) [ 2 ] ) ) ;
} else {
pan_counter - - ;
}
if ( zoom_counter = = 0 ) {
m_map - > setZoom ( util : : map_val < float > ( velocity_filter . update ( velocity ) , 0 , 30 , MAX_ZOOM , MIN_ZOOM ) ) ;
} else {
zoom_counter - - ;
}
// Update current location marker
auto point = coordinate_to_collection ( coordinate ) ;
QMapbox : : Feature feature1 ( QMapbox : : Feature : : PointType , point , { } , { } ) ;
QVariantMap carPosSource ;
carPosSource [ " type " ] = " geojson " ;
carPosSource [ " data " ] = QVariant : : fromValue < QMapbox : : Feature > ( feature1 ) ;
m_map - > updateSource ( " carPosSource " , carPosSource ) ;
// Update model path
if ( DRAW_MODEL_PATH ) {
auto model = ( * sm ) [ " modelV2 " ] . getModelV2 ( ) ;
auto path_points = model_to_collection ( location . getCalibratedOrientationECEF ( ) , location . getPositionECEF ( ) , model . getPosition ( ) ) ;
QMapbox : : Feature feature2 ( QMapbox : : Feature : : LineStringType , path_points , { } , { } ) ;
QVariantMap modelPathSource ;
modelPathSource [ " type " ] = " geojson " ;
modelPathSource [ " data " ] = QVariant : : fromValue < QMapbox : : Feature > ( feature2 ) ;
m_map - > updateSource ( " modelPathSource " , modelPathSource ) ;
}
}
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,30 +262,33 @@ 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 ;
if ( * new_destination ! = nav_destination ) {
nav_destination = * new_destination ;
setVisible ( true ) ; // Show map on destination set/change
return true ;
}
}
if ( ! segment . isValid ( ) ) {
return true ;
@ -385,16 +417,27 @@ MapInstructions::MapInstructions(QWidget * parent) : QWidget(parent){
void MapInstructions : : updateDistance ( float d ) {
QString distance_str ;
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 {
float miles = d * METER_2_MILE ;
float feet = d * METER_2_FOOT ;
if ( feet > 500 ) {
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 ) ;
}