|
|
@ -39,6 +39,7 @@ MapWindow::MapWindow(const QMapboxGLSettings &settings) : m_settings(settings) { |
|
|
|
map_instructions = new MapInstructions(this); |
|
|
|
map_instructions = new MapInstructions(this); |
|
|
|
connect(this, &MapWindow::instructionsChanged, map_instructions, &MapInstructions::updateInstructions); |
|
|
|
connect(this, &MapWindow::instructionsChanged, map_instructions, &MapInstructions::updateInstructions); |
|
|
|
connect(this, &MapWindow::distanceChanged, map_instructions, &MapInstructions::updateDistance); |
|
|
|
connect(this, &MapWindow::distanceChanged, map_instructions, &MapInstructions::updateDistance); |
|
|
|
|
|
|
|
connect(this, &MapWindow::GPSValidChanged, map_instructions, &MapInstructions::updateGPSValid); |
|
|
|
map_instructions->setFixedWidth(width()); |
|
|
|
map_instructions->setFixedWidth(width()); |
|
|
|
|
|
|
|
|
|
|
|
map_eta = new MapETA(this); |
|
|
|
map_eta = new MapETA(this); |
|
|
@ -121,8 +122,10 @@ void MapWindow::timerUpdate() { |
|
|
|
auto location = (*sm)["liveLocationKalman"].getLiveLocationKalman(); |
|
|
|
auto location = (*sm)["liveLocationKalman"].getLiveLocationKalman(); |
|
|
|
gps_ok = location.getGpsOK(); |
|
|
|
gps_ok = location.getGpsOK(); |
|
|
|
|
|
|
|
|
|
|
|
// Update map location, orientation and zoom on valid localizer output
|
|
|
|
bool localizer_valid = location.getStatus() == cereal::LiveLocationKalman::Status::VALID; |
|
|
|
if (location.getStatus() == cereal::LiveLocationKalman::Status::VALID) { |
|
|
|
emit GPSValidChanged(localizer_valid); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (localizer_valid) { |
|
|
|
auto pos = location.getPositionGeodetic(); |
|
|
|
auto pos = location.getPositionGeodetic(); |
|
|
|
auto orientation = location.getOrientationNED(); |
|
|
|
auto orientation = location.getOrientationNED(); |
|
|
|
|
|
|
|
|
|
|
@ -165,61 +168,59 @@ void MapWindow::timerUpdate() { |
|
|
|
modelPathSource["data"] = QVariant::fromValue<QMapbox::Feature>(feature2); |
|
|
|
modelPathSource["data"] = QVariant::fromValue<QMapbox::Feature>(feature2); |
|
|
|
m_map->updateSource("modelPathSource", modelPathSource); |
|
|
|
m_map->updateSource("modelPathSource", modelPathSource); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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")) { |
|
|
|
|
|
|
|
float along_geometry = distance_along_geometry(segment.path(), to_QGeoCoordinate(last_position)); |
|
|
|
|
|
|
|
float distance = std::max(0.0f, float(segment.distance()) - along_geometry); |
|
|
|
|
|
|
|
emit distanceChanged(distance); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_map->setPitch(MAX_PITCH); // TODO: smooth pitching based on maneuver distance
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto banner = attrs["mapbox.banner_instructions"].toList(); |
|
|
|
if (segment.isValid()) { |
|
|
|
if (banner.size()) { |
|
|
|
// Show route instructions
|
|
|
|
map_instructions->setVisible(true); |
|
|
|
auto cur_maneuver = segment.maneuver(); |
|
|
|
|
|
|
|
auto attrs = cur_maneuver.extendedAttributes(); |
|
|
|
auto banner_0 = banner[0].toMap(); |
|
|
|
if (cur_maneuver.isValid() && attrs.contains("mapbox.banner_instructions")) { |
|
|
|
float show_at = banner_0["distance_along_geometry"].toDouble(); |
|
|
|
float along_geometry = distance_along_geometry(segment.path(), to_QGeoCoordinate(*last_position)); |
|
|
|
emit instructionsChanged(banner_0, distance < show_at); |
|
|
|
float distance = std::max(0.0f, float(segment.distance()) - along_geometry); |
|
|
|
|
|
|
|
emit distanceChanged(distance); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_map->setPitch(MAX_PITCH); // TODO: smooth pitching based on maneuver distance
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto banner = attrs["mapbox.banner_instructions"].toList(); |
|
|
|
|
|
|
|
if (banner.size()) { |
|
|
|
|
|
|
|
auto banner_0 = banner[0].toMap(); |
|
|
|
|
|
|
|
float show_at = banner_0["distance_along_geometry"].toDouble(); |
|
|
|
|
|
|
|
emit instructionsChanged(banner_0, distance < show_at); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto next_segment = segment.nextRouteSegment(); |
|
|
|
// Handle transition to next route segment
|
|
|
|
if (next_segment.isValid()) { |
|
|
|
auto next_segment = segment.nextRouteSegment(); |
|
|
|
auto next_maneuver = next_segment.maneuver(); |
|
|
|
if (next_segment.isValid()) { |
|
|
|
if (next_maneuver.isValid()) { |
|
|
|
auto next_maneuver = next_segment.maneuver(); |
|
|
|
float next_maneuver_distance = next_maneuver.position().distanceTo(to_QGeoCoordinate(last_position)); |
|
|
|
if (next_maneuver.isValid()) { |
|
|
|
// Switch to next route segment
|
|
|
|
float next_maneuver_distance = next_maneuver.position().distanceTo(to_QGeoCoordinate(*last_position)); |
|
|
|
if (next_maneuver_distance < REROUTE_DISTANCE && next_maneuver_distance > last_maneuver_distance) { |
|
|
|
// Switch to next route segment
|
|
|
|
segment = next_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; |
|
|
|
recompute_backoff = std::max(0, recompute_backoff - 1); |
|
|
|
|
|
|
|
recompute_countdown = 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
last_maneuver_distance = next_maneuver_distance; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Destination reached
|
|
|
|
|
|
|
|
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(); |
|
|
|
} |
|
|
|
} |
|
|
|
last_maneuver_distance = next_maneuver_distance; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
Params().remove("NavDestination"); |
|
|
|
map_instructions->setVisible(false); |
|
|
|
|
|
|
|
|
|
|
|
// Clear route if driving away from destination
|
|
|
|
|
|
|
|
float d = segment.maneuver().position().distanceTo(to_QGeoCoordinate(last_position)); |
|
|
|
|
|
|
|
if (d > REROUTE_DISTANCE) { |
|
|
|
|
|
|
|
clearRoute(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
update(); |
|
|
|
update(); |
|
|
|
|
|
|
|
|
|
|
|
if (!segment.isValid()) { |
|
|
|
|
|
|
|
map_instructions->setVisible(false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -230,7 +231,12 @@ void MapWindow::resizeGL(int w, int h) { |
|
|
|
void MapWindow::initializeGL() { |
|
|
|
void MapWindow::initializeGL() { |
|
|
|
m_map.reset(new QMapboxGL(nullptr, m_settings, size(), 1)); |
|
|
|
m_map.reset(new QMapboxGL(nullptr, m_settings, size(), 1)); |
|
|
|
|
|
|
|
|
|
|
|
m_map->setCoordinateZoom(last_position, MAX_ZOOM); |
|
|
|
if (last_position) { |
|
|
|
|
|
|
|
m_map->setCoordinateZoom(*last_position, MAX_ZOOM); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
m_map->setCoordinateZoom(QMapbox::Coordinate(64.31990695292795, -149.79038934046247), MIN_ZOOM); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
m_map->setMargins({0, 350, 0, 50}); |
|
|
|
m_map->setMargins({0, 350, 0, 50}); |
|
|
|
m_map->setPitch(MIN_PITCH); |
|
|
|
m_map->setPitch(MIN_PITCH); |
|
|
|
m_map->setStyleUrl("mapbox://styles/pd0wm/cknuhcgvr0vs817o1akcx6pek"); // Larger fonts
|
|
|
|
m_map->setStyleUrl("mapbox://styles/pd0wm/cknuhcgvr0vs817o1akcx6pek"); // Larger fonts
|
|
|
@ -255,6 +261,11 @@ static float get_time_typical(const QGeoRouteSegment &segment) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MapWindow::recomputeRoute() { |
|
|
|
void MapWindow::recomputeRoute() { |
|
|
|
|
|
|
|
// Last position is valid if read from param or from GPS
|
|
|
|
|
|
|
|
if (!last_position) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool should_recompute = shouldRecompute(); |
|
|
|
bool should_recompute = shouldRecompute(); |
|
|
|
auto new_destination = coordinate_from_param("NavDestination"); |
|
|
|
auto new_destination = coordinate_from_param("NavDestination"); |
|
|
|
|
|
|
|
|
|
|
@ -286,7 +297,7 @@ void MapWindow::recomputeRoute() { |
|
|
|
|
|
|
|
|
|
|
|
void MapWindow::updateETA() { |
|
|
|
void MapWindow::updateETA() { |
|
|
|
if (segment.isValid()) { |
|
|
|
if (segment.isValid()) { |
|
|
|
float progress = distance_along_geometry(segment.path(), to_QGeoCoordinate(last_position)) / segment.distance(); |
|
|
|
float progress = distance_along_geometry(segment.path(), to_QGeoCoordinate(*last_position)) / segment.distance(); |
|
|
|
float total_distance = segment.distance() * (1.0 - progress); |
|
|
|
float total_distance = segment.distance() * (1.0 - progress); |
|
|
|
float total_time = segment.travelTime() * (1.0 - progress); |
|
|
|
float total_time = segment.travelTime() * (1.0 - progress); |
|
|
|
float total_time_typical = get_time_typical(segment) * (1.0 - progress); |
|
|
|
float total_time_typical = get_time_typical(segment) * (1.0 - progress); |
|
|
@ -307,7 +318,7 @@ void MapWindow::updateETA() { |
|
|
|
void MapWindow::calculateRoute(QMapbox::Coordinate destination) { |
|
|
|
void MapWindow::calculateRoute(QMapbox::Coordinate destination) { |
|
|
|
LOGW("calculating route"); |
|
|
|
LOGW("calculating route"); |
|
|
|
nav_destination = destination; |
|
|
|
nav_destination = destination; |
|
|
|
QGeoRouteRequest request(to_QGeoCoordinate(last_position), to_QGeoCoordinate(destination)); |
|
|
|
QGeoRouteRequest request(to_QGeoCoordinate(*last_position), to_QGeoCoordinate(destination)); |
|
|
|
request.setFeatureWeight(QGeoRouteRequest::TrafficFeature, QGeoRouteRequest::AvoidFeatureWeight); |
|
|
|
request.setFeatureWeight(QGeoRouteRequest::TrafficFeature, QGeoRouteRequest::AvoidFeatureWeight); |
|
|
|
|
|
|
|
|
|
|
|
if (last_bearing) { |
|
|
|
if (last_bearing) { |
|
|
@ -362,7 +373,7 @@ bool MapWindow::shouldRecompute() { |
|
|
|
// Compute closest distance to all line segments in the current path
|
|
|
|
// Compute closest distance to all line segments in the current path
|
|
|
|
float min_d = REROUTE_DISTANCE + 1; |
|
|
|
float min_d = REROUTE_DISTANCE + 1; |
|
|
|
auto path = segment.path(); |
|
|
|
auto path = segment.path(); |
|
|
|
auto cur = to_QGeoCoordinate(last_position); |
|
|
|
auto cur = to_QGeoCoordinate(*last_position); |
|
|
|
for (size_t i = 0; i < path.size() - 1; i++) { |
|
|
|
for (size_t i = 0; i < path.size() - 1; i++) { |
|
|
|
auto a = path[i]; |
|
|
|
auto a = path[i]; |
|
|
|
auto b = path[i+1]; |
|
|
|
auto b = path[i+1]; |
|
|
@ -512,9 +523,24 @@ void MapInstructions::updateDistance(float d) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
distance->setAlignment(Qt::AlignLeft); |
|
|
|
distance->setText(distance_str); |
|
|
|
distance->setText(distance_str); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MapInstructions::updateGPSValid(bool valid) { |
|
|
|
|
|
|
|
if (!valid) { |
|
|
|
|
|
|
|
primary->setText(""); |
|
|
|
|
|
|
|
distance->setText("GPS not available"); |
|
|
|
|
|
|
|
distance->setAlignment(Qt::AlignCenter); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
secondary->setVisible(false); |
|
|
|
|
|
|
|
icon_01->setVisible(false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setVisible(true); |
|
|
|
|
|
|
|
adjustSize(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void MapInstructions::updateInstructions(QMap<QString, QVariant> banner, bool full) { |
|
|
|
void MapInstructions::updateInstructions(QMap<QString, QVariant> banner, bool full) { |
|
|
|
// Need multiple calls to adjustSize for it to properly resize
|
|
|
|
// Need multiple calls to adjustSize for it to properly resize
|
|
|
|
// seems like it takes a little bit of time for the images to change and
|
|
|
|
// seems like it takes a little bit of time for the images to change and
|
|
|
@ -539,6 +565,7 @@ void MapInstructions::updateInstructions(QMap<QString, QVariant> banner, bool fu |
|
|
|
QPixmap pix(fn); |
|
|
|
QPixmap pix(fn); |
|
|
|
icon_01->setPixmap(pix.scaledToWidth(200, Qt::SmoothTransformation)); |
|
|
|
icon_01->setPixmap(pix.scaledToWidth(200, Qt::SmoothTransformation)); |
|
|
|
icon_01->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); |
|
|
|
icon_01->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); |
|
|
|
|
|
|
|
icon_01->setVisible(true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Parse components (e.g. lanes, exit number)
|
|
|
|
// Parse components (e.g. lanes, exit number)
|
|
|
@ -601,8 +628,11 @@ void MapInstructions::updateInstructions(QMap<QString, QVariant> banner, bool fu |
|
|
|
primary->setText(primary_str); |
|
|
|
primary->setText(primary_str); |
|
|
|
secondary->setVisible(secondary_str.length() > 0); |
|
|
|
secondary->setVisible(secondary_str.length() > 0); |
|
|
|
secondary->setText(secondary_str); |
|
|
|
secondary->setText(secondary_str); |
|
|
|
adjustSize(); |
|
|
|
|
|
|
|
last_banner = banner; |
|
|
|
last_banner = banner; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setVisible(true); |
|
|
|
|
|
|
|
adjustSize(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
MapETA::MapETA(QWidget * parent) : QWidget(parent) { |
|
|
|
MapETA::MapETA(QWidget * parent) : QWidget(parent) { |
|
|
|