diff --git a/common/params.cc b/common/params.cc index 3fc1935..1680460 100644 --- a/common/params.cc +++ b/common/params.cc @@ -313,6 +313,7 @@ std::unordered_map keys = { {"MapsSelected", PERSISTENT}, {"MapSpeedLimit", PERSISTENT}, {"MapSpeedLimitControl", PERSISTENT}, + {"MapStyle", PERSISTENT}, {"MapTargetLatA", PERSISTENT}, {"MapTargetVelocities", PERSISTENT}, {"Model", PERSISTENT}, diff --git a/selfdrive/frogpilot/ui/visual_settings.cc b/selfdrive/frogpilot/ui/visual_settings.cc index 083a0b5..4370b93 100644 --- a/selfdrive/frogpilot/ui/visual_settings.cc +++ b/selfdrive/frogpilot/ui/visual_settings.cc @@ -53,6 +53,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilot {"DriveStats", "Drive Stats In Home Screen", "Display your device's drive stats in the home screen.", ""}, {"FullMap", "Full Sized Map", "Maximize the size of the map in the onroad UI.", ""}, {"HideSpeed", "Hide Speed", "Hide the speed indicator in the onroad UI. Additional toggle allows it to be hidden/shown via tapping the speed itself.", ""}, + {"MapStyle", "Map Style", "Use a custom map style to be used for 'Navigate on openpilot'.", ""}, {"ScreenManagement", "Screen Management", "Manage your screen's brightness, timeout settings, and hide specific onroad UI elements.", "../frogpilot/assets/toggle_icons/icon_light.png"}, {"HideUIElements", "Hide UI Elements", "Hide the selected UI elements from the onroad screen.", ""}, @@ -172,12 +173,46 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilot for (auto &[key, toggle] : toggles) { toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end()); } + mapStyleButton->setVisible(true); }); toggle = qolToggle; } else if (param == "HideSpeed") { std::vector hideSpeedToggles{"HideSpeedUI"}; std::vector hideSpeedToggleNames{tr("Control Via UI")}; toggle = new FrogPilotParamToggleControl(param, title, desc, icon, hideSpeedToggles, hideSpeedToggleNames); + } else if (param == "MapStyle") { + QMap styleMap = { + {0, tr("Stock openpilot")}, + {1, tr("Mapbox Streets")}, + {2, tr("Mapbox Outdoors")}, + {3, tr("Mapbox Light")}, + {4, tr("Mapbox Dark")}, + {5, tr("Mapbox Satellite")}, + {6, tr("Mapbox Satellite Streets")}, + {7, tr("Mapbox Navigation Day")}, + {8, tr("Mapbox Navigation Night")}, + {9, tr("Mapbox Traffic Night")}, + {10, tr("mike854's (Satellite hybrid)")}, + }; + + QStringList styles = styleMap.values(); + + mapStyleButton = new ButtonControl(title, tr("SELECT"), desc); + QObject::connect(mapStyleButton, &ButtonControl::clicked, this, [this, styleMap]() { + QStringList styles = styleMap.values(); + QString selection = MultiOptionDialog::getSelection(tr("Select a map style"), styles, "", this); + if (!selection.isEmpty()) { + int selectedStyle = styleMap.key(selection); + params.putInt("MapStyle", selectedStyle); + mapStyleButton->setValue(selection); + updateToggles(); + } + }); + + int currentStyle = params.getInt("MapStyle"); + mapStyleButton->setValue(styleMap[currentStyle]); + + addItem(mapStyleButton); } else if (param == "ScreenManagement") { FrogPilotParamManageControl *screenToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); @@ -307,14 +342,20 @@ void FrogPilotVisualsPanel::updateMetric() { } void FrogPilotVisualsPanel::parentToggleClicked() { + mapStyleButton->setVisible(false); + openParentToggle(); } void FrogPilotVisualsPanel::subParentToggleClicked() { + mapStyleButton->setVisible(false); + openSubParentToggle(); } void FrogPilotVisualsPanel::hideSubToggles() { + mapStyleButton->setVisible(false); + for (auto &[key, toggle] : toggles) { bool subToggles = alertVolumeControlKeys.find(key.c_str()) != alertVolumeControlKeys.end() || customAlertsKeys.find(key.c_str()) != customAlertsKeys.end() || diff --git a/selfdrive/frogpilot/ui/visual_settings.h b/selfdrive/frogpilot/ui/visual_settings.h index 96d4a2c..0418b56 100644 --- a/selfdrive/frogpilot/ui/visual_settings.h +++ b/selfdrive/frogpilot/ui/visual_settings.h @@ -28,12 +28,14 @@ private: void updateState(const UIState &s); void updateToggles(); + ButtonControl *mapStyleButton; + std::set alertVolumeControlKeys = {"EngageVolume", "DisengageVolume", "RefuseVolume", "PromptVolume", "PromptDistractedVolume", "WarningSoftVolume", "WarningImmediateVolume"}; std::set customAlertsKeys = {"GreenLightAlert", "LeadDepartingAlert", "LoudBlindspotAlert", "SpeedLimitChangedAlert"}; std::set customOnroadUIKeys = {"AccelerationPath", "AdjacentPath", "BlindSpotPath", "FPSCounter", "LeadInfo", "PedalsOnUI", "RoadNameUI"}; std::set customThemeKeys = {"HolidayThemes", "CustomColors", "CustomIcons", "CustomSignals", "CustomSounds"}; std::set modelUIKeys = {"DynamicPathWidth", "HideLeadMarker", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"}; - std::set qolKeys = {"DriveStats", "FullMap", "HideSpeed"}; + std::set qolKeys = {"DriveStats", "FullMap", "HideSpeed", "MapStyle"}; std::set screenKeys = {"HideUIElements", "ScreenBrightness", "ScreenBrightnessOnroad", "ScreenRecorder", "ScreenTimeout", "ScreenTimeoutOnroad", "StandbyMode"}; std::map toggles; diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py old mode 100755 new mode 100644 diff --git a/selfdrive/ui/qt/maps/map.cc b/selfdrive/ui/qt/maps/map.cc index c1f98d6..bd9a4a6 100644 --- a/selfdrive/ui/qt/maps/map.cc +++ b/selfdrive/ui/qt/maps/map.cc @@ -54,18 +54,7 @@ MapWindow::~MapWindow() { void MapWindow::initLayers() { // This doesn't work from initializeGL - if (!m_map->layerExists("modelPathLayer")) { - qDebug() << "Initializing modelPathLayer"; - QVariantMap modelPath; - //modelPath["id"] = "modelPathLayer"; - modelPath["type"] = "line"; - modelPath["source"] = "modelPathSource"; - m_map->addLayer("modelPathLayer", modelPath); - m_map->setPaintProperty("modelPathLayer", "line-color", QColor("red")); - m_map->setPaintProperty("modelPathLayer", "line-width", 5.0); - m_map->setLayoutProperty("modelPathLayer", "line-cap", "round"); - } - if (!m_map->layerExists("navLayer")) { + if (!m_map->layerExists("navLayer")) { qDebug() << "Initializing navLayer"; QVariantMap nav; nav["type"] = "line"; @@ -79,6 +68,17 @@ void MapWindow::initLayers() { m_map->setPaintProperty("navLayer", "line-width", 7.5); m_map->setLayoutProperty("navLayer", "line-cap", "round"); } +if (!m_map->layerExists("modelPathLayer")) { + qDebug() << "Initializing modelPathLayer"; + QVariantMap modelPath; + //modelPath["id"] = "modelPathLayer"; + modelPath["type"] = "line"; + modelPath["source"] = "modelPathSource"; + m_map->addLayer("modelPathLayer", modelPath); + m_map->setPaintProperty("modelPathLayer", "line-color", QColor("red")); + m_map->setPaintProperty("modelPathLayer", "line-width", 5.0); + m_map->setLayoutProperty("modelPathLayer", "line-cap", "round"); + } if (!m_map->layerExists("pinLayer")) { qDebug() << "Initializing pinLayer"; m_map->addImage("default_marker", QImage("../assets/navigation/default_marker.svg")); @@ -109,6 +109,50 @@ void MapWindow::initLayers() { // TODO: remove, symbol-sort-key does not seem to matter outside of each layer m_map->setLayoutProperty("carPosLayer", "symbol-sort-key", 0); } + + if (!m_map->layerExists("buildingsLayer")) { + qDebug() << "Initializing buildingsLayer"; + QVariantMap buildings; + buildings["id"] = "buildingsLayer"; + buildings["source"] = "composite"; + buildings["source-layer"] = "building"; + buildings["type"] = "fill-extrusion"; + buildings["minzoom"] = 15; + m_map->addLayer("buildingsLayer", buildings); + m_map->setFilter("buildingsLayer", QVariantList({"==", "extrude", "true"})); + + QVariantList fillExtrusionHight = { + "interpolate", + QVariantList{"linear"}, + QVariantList{"zoom"}, + 15, 0, + 15.05, QVariantList{"get", "height"} + }; + + QVariantList fillExtrusionBase = { + "interpolate", + QVariantList{"linear"}, + QVariantList{"zoom"}, + 15, 0, + 15.05, QVariantList{"get", "min_height"} + }; + + QVariantList fillExtrusionOpacity = { + "interpolate", + QVariantList{"linear"}, + QVariantList{"zoom"}, + 15, 0, + 15.5, .6, + 17, .6, + 20, 0 + }; + + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-color", QColor("grey")); + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-opacity", fillExtrusionOpacity); + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-height", fillExtrusionHight); + m_map->setPaintProperty("buildingsLayer", "fill-extrusion-base", fillExtrusionBase); + m_map->setLayoutProperty("buildingsLayer", "visibility", "visible"); + } } void MapWindow::updateState(const UIState &s) { @@ -150,6 +194,17 @@ void MapWindow::updateState(const UIState &s) { last_bearing = RAD2DEG(locationd_orientation.getValue()[2]); velocity_filter.update(std::max(10.0, locationd_velocity.getValue()[0])); } +} + // Credit to jakethesnake420 + if (loaded_once && (sm.rcv_frame("uiPlan") != model_rcv_frame)) { + auto locationd_location = sm["liveLocationKalman"].getLiveLocationKalman(); + auto model_path = model_to_collection(locationd_location.getCalibratedOrientationECEF(), locationd_location.getPositionECEF(), sm["uiPlan"].getUiPlan().getPosition()); + QMapLibre::Feature model_path_feature(QMapLibre::Feature::LineStringType, model_path, {}, {}); + QVariantMap modelV2Path; + modelV2Path["type"] = "geojson"; + modelV2Path["data"] = QVariant::fromValue(model_path_feature); + m_map->updateSource("modelPathSource", modelV2Path); + model_rcv_frame = sm.rcv_frame("uiPlan"); } if (sm.updated("navRoute") && sm["navRoute"].getNavRoute().getCoordinates().size()) { @@ -237,6 +292,30 @@ void MapWindow::updateState(const UIState &s) { route_rcv_frame = sm.rcv_frame("navRoute"); updateDestinationMarker(); } + + // Map Styling - Credit goes to OPKR! + int map_style = uiState()->scene.map_style; + + if (map_style != previous_map_style) { + std::unordered_map styleUrls = { + {0, "mapbox://styles/commaai/clkqztk0f00ou01qyhsa5bzpj"}, // Stock openpilot + {1, "mapbox://styles/mapbox/streets-v11"}, // Mapbox Streets + {2, "mapbox://styles/mapbox/outdoors-v11"}, // Mapbox Outdoors + {3, "mapbox://styles/mapbox/light-v10"}, // Mapbox Light + {4, "mapbox://styles/mapbox/dark-v10"}, // Mapbox Dark + {5, "mapbox://styles/mapbox/satellite-v9"}, // Mapbox Satellite + {6, "mapbox://styles/mapbox/satellite-streets-v11"}, // Mapbox Satellite Streets + {7, "mapbox://styles/mapbox/navigation-day-v1"}, // Mapbox Navigation Day + {8, "mapbox://styles/mapbox/navigation-night-v1"}, // Mapbox Navigation Night + {9, "mapbox://styles/mapbox/traffic-night-v2"}, // Mapbox Traffic Night + {10, "mapbox://styles/mike854/clt0hm8mw01ok01p4blkr27jp"}, // mike854's (Satellite hybrid) + }; + + std::unordered_map::iterator it = styleUrls.find(map_style); + m_map->setStyleUrl(QString::fromStdString(it->second)); + } + + previous_map_style = map_style; } void MapWindow::setError(const QString &err_str) { diff --git a/selfdrive/ui/qt/maps/map.h b/selfdrive/ui/qt/maps/map.h index 5849b64..2447b8d 100644 --- a/selfdrive/ui/qt/maps/map.h +++ b/selfdrive/ui/qt/maps/map.h @@ -77,10 +77,13 @@ private: void clearRoute(); void updateDestinationMarker(); uint64_t route_rcv_frame = 0; + uint64_t model_rcv_frame = 0; // FrogPilot variables Params params; + int previous_map_style; + private slots: void updateState(const UIState &s); diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index 057f121..a74cade 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -368,6 +368,7 @@ void ui_update_frogpilot_params(UIState *s) { scene.full_map = quality_of_life_visuals && params.getBool("FullMap"); scene.hide_speed = quality_of_life_visuals && params.getBool("HideSpeed"); scene.hide_speed_ui = scene.hide_speed && params.getBool("HideSpeedUI"); + scene.map_style = quality_of_life_visuals ? params.getInt("MapStyle") : 0; scene.rotating_wheel = params.getBool("RotatingWheel"); diff --git a/selfdrive/ui/ui.h b/selfdrive/ui/ui.h index 15be138..0e372b8 100644 --- a/selfdrive/ui/ui.h +++ b/selfdrive/ui/ui.h @@ -255,6 +255,7 @@ typedef struct UIScene { int custom_icons; int custom_signals; int desired_follow; + int map_style; int obstacle_distance; int obstacle_distance_stock; int screen_brightness;