You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							149 lines
						
					
					
						
							5.0 KiB
						
					
					
				
			
		
		
	
	
							149 lines
						
					
					
						
							5.0 KiB
						
					
					
				| #include "selfdrive/ui/qt/maps/map_instructions.h"
 | |
| 
 | |
| #include <QDir>
 | |
| #include <QVBoxLayout>
 | |
| 
 | |
| #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);
 | |
|   }
 | |
| 
 | |
|   // Hide distance after arrival
 | |
|   distance->setVisible(type != "arrive" || instruction.getManeuverDistance() > 0);
 | |
| 
 | |
|   // 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);
 | |
| }
 | |
| 
 |