#include "selfdrive/ui/qt/maps/map_instructions.h" #include #include #include "selfdrive/ui/ui.h" const QString ICON_SUFFIX = ".png"; MapInstructions::MapInstructions(QWidget *parent) : QWidget(parent) { is_rhd = Params().getBool("IsRhdDetected"); QHBoxLayout *main_layout = new QHBoxLayout(this); main_layout->setContentsMargins(11, 50, 11, 11); main_layout->addWidget(icon_01 = new QLabel, 0, Qt::AlignTop); QWidget *right_container = new QWidget(this); right_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); QVBoxLayout *layout = new QVBoxLayout(right_container); layout->addWidget(distance = new QLabel); distance->setStyleSheet(R"(font-size: 90px;)"); layout->addWidget(primary = new QLabel); primary->setStyleSheet(R"(font-size: 60px;)"); primary->setWordWrap(true); layout->addWidget(secondary = new QLabel); secondary->setStyleSheet(R"(font-size: 50px;)"); secondary->setWordWrap(true); layout->addLayout(lane_layout = new QHBoxLayout); main_layout->addWidget(right_container); setStyleSheet("color:white"); QPalette pal = palette(); pal.setColor(QPalette::Background, QColor(0, 0, 0, 150)); setAutoFillBackground(true); setPalette(pal); buildPixmapCache(); } void MapInstructions::buildPixmapCache() { QDir dir("../assets/navigation"); for (QString fn : dir.entryList({"*" + ICON_SUFFIX}, QDir::Files)) { QPixmap pm(dir.filePath(fn)); QString key = fn.left(fn.size() - ICON_SUFFIX.length()); pm = pm.scaledToWidth(200, Qt::SmoothTransformation); // Maneuver icons pixmap_cache[key] = pm; // lane direction icons if (key.contains("turn_")) { pixmap_cache["lane_" + key] = pm.scaled({125, 125}, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } // for rhd, reflect direction and then flip if (key.contains("_left")) { pixmap_cache["rhd_" + key.replace("_left", "_right")] = pm.transformed(QTransform().scale(-1, 1)); } else if (key.contains("_right")) { pixmap_cache["rhd_" + key.replace("_right", "_left")] = pm.transformed(QTransform().scale(-1, 1)); } } } QString MapInstructions::getDistance(float d) { d = std::max(d, 0.0f); if (uiState()->scene.is_metric) { return (d > 500) ? QString::number(d / 1000, 'f', 1) + tr(" km") : QString::number(50 * int(d / 50)) + tr(" m"); } else { float feet = d * METER_TO_FOOT; return (feet > 500) ? QString::number(d * METER_TO_MILE, 'f', 1) + tr(" mi") : QString::number(50 * int(feet / 50)) + tr(" ft"); } } void MapInstructions::updateInstructions(cereal::NavInstruction::Reader instruction) { setUpdatesEnabled(false); // Show instruction text QString primary_str = QString::fromStdString(instruction.getManeuverPrimaryText()); QString secondary_str = QString::fromStdString(instruction.getManeuverSecondaryText()); primary->setText(primary_str); secondary->setVisible(secondary_str.length() > 0); secondary->setText(secondary_str); distance->setText(getDistance(instruction.getManeuverDistance())); // Show arrow with direction QString type = QString::fromStdString(instruction.getManeuverType()); QString modifier = QString::fromStdString(instruction.getManeuverModifier()); if (!type.isEmpty()) { QString fn = "direction_" + type; if (!modifier.isEmpty()) { fn += "_" + modifier; } fn = fn.replace(' ', '_'); bool rhd = is_rhd && (fn.contains("_left") || fn.contains("_right")); icon_01->setPixmap(pixmap_cache[!rhd ? fn : "rhd_" + fn]); icon_01->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); icon_01->setVisible(true); } // Show lanes auto lanes = instruction.getLanes(); for (int i = 0; i < lanes.size(); ++i) { bool active = lanes[i].getActive(); // TODO: only use active direction if active bool left = false, straight = false, right = false; for (auto const &direction : lanes[i].getDirections()) { left |= direction == cereal::NavInstruction::Direction::LEFT; right |= direction == cereal::NavInstruction::Direction::RIGHT; straight |= direction == cereal::NavInstruction::Direction::STRAIGHT; } // TODO: Make more images based on active direction and combined directions QString fn = "lane_direction_"; if (left) { fn += "turn_left"; } else if (right) { fn += "turn_right"; } else if (straight) { fn += "turn_straight"; } if (!active) { fn += "_inactive"; } QLabel *label = (i < lane_labels.size()) ? lane_labels[i] : lane_labels.emplace_back(new QLabel); if (!label->parentWidget()) { lane_layout->addWidget(label); } label->setPixmap(pixmap_cache[fn]); label->setVisible(true); } for (int i = lanes.size(); i < lane_labels.size(); ++i) { lane_labels[i]->setVisible(false); } setUpdatesEnabled(true); setVisible(true); }