Merge pull request #40 from dpaulat/feature/maptiler

Support MapTiler
This commit is contained in:
Dan Paulat 2023-04-30 19:56:55 -05:00 committed by GitHub
commit 9019aa5e33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 568 additions and 103 deletions

View file

@ -31,6 +31,7 @@ jobs:
msvc_version: 2022
qt_version: 6.5.0
qt_arch: win64_msvc2019_64
qt_modules: qtimageformats
qt_tools: ''
conan_arch: x86_64
conan_compiler: Visual Studio
@ -46,6 +47,7 @@ jobs:
compiler: gcc
qt_version: 6.5.0
qt_arch: gcc_64
qt_modules: qtimageformats
qt_tools: ''
conan_arch: x86_64
conan_compiler: gcc
@ -74,6 +76,7 @@ jobs:
with:
version: ${{ matrix.qt_version }}
arch: ${{ matrix.qt_arch }}
modules: ${{ matrix.qt_modules }}
tools: ${{ matrix.qt_tools }}
- name: Setup MSVC

2
.gitmodules vendored
View file

@ -1,6 +1,6 @@
[submodule "external/mapbox-gl-native"]
path = external/mapbox-gl-native
url = https://github.com/maplibre/maplibre-gl-native.git
url = https://github.com/dpaulat/maplibre-gl-native.git
[submodule "external/cmake-conan"]
path = external/cmake-conan
url = https://github.com/conan-io/cmake-conan.git

View file

@ -15,7 +15,7 @@ Supercell Wx uses code from the following dependencies:
| [bzip2](https://sourceware.org/bzip2/) | [bzip2 and libbzip2 License v1.0.6](https://spdx.org/licenses/bzip2-1.0.6.html) |
| [cmake-conan](https://github.com/conan-io/cmake-conan) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [cpr](https://github.com/libcpr/cpr) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [CSS Color Parser](https://github.com/deanm/css-color-parser-js) | [MIT License](https://spdx.org/licenses/MIT.html) | Ported to C++ for MapLibre GL Native |
| [CSS Color Parser](https://github.com/deanm/css-color-parser-js) | [MIT License](https://spdx.org/licenses/MIT.html) | Ported to C++ for MapLibre Native |
| [Date](https://github.com/HowardHinnant/date) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [Dear ImGui](https://github.com/ocornut/imgui) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [FreeType](https://freetype.org/) | [Freetype Project License](https://spdx.org/licenses/FTL.html) |
@ -29,8 +29,8 @@ Supercell Wx uses code from the following dependencies:
| [libiconv](https://www.gnu.org/software/libiconv/) | [GNU Lesser General Public License v2.1 or later](https://spdx.org/licenses/LGPL-2.1-or-later.html) |
| [libpng](http://libpng.org/pub/png/libpng.html) | [PNG Reference Library version 2](https://spdx.org/licenses/libpng-2.0.html) |
| [libxml2](http://xmlsoft.org/) | [MIT License](https://spdx.org/licenses/MIT.html) |
| [MapLibre GL Native](https://maplibre.org/projects/maplibre-native/) | [BSD 2-Clause "Simplified" License](https://spdx.org/licenses/BSD-2-Clause.html) |
| [nunicode](https://bitbucket.org/alekseyt/nunicode/src/master/) | [MIT License](https://spdx.org/licenses/MIT.html) | Modified for MapLibre GL Native |
| [MapLibre Native](https://maplibre.org/projects/maplibre-native/) | [BSD 2-Clause "Simplified" License](https://spdx.org/licenses/BSD-2-Clause.html) |
| [nunicode](https://bitbucket.org/alekseyt/nunicode/src/master/) | [MIT License](https://spdx.org/licenses/MIT.html) | Modified for MapLibre Native |
| [OpenSSL](https://www.openssl.org/) | [OpenSSL License](https://spdx.org/licenses/OpenSSL.html) |
| [Qt](https://www.qt.io/) | [GNU Lesser General Public License v3.0 only](https://spdx.org/licenses/LGPL-3.0-only.html) | Qt Core, Qt GUI, Qt Network, Qt OpenGL, Qt SQL, Qt SVG, Qt Widgets<br/>Additional Licenses: https://doc.qt.io/qt-6/licenses-used-in-qt.html |
| [spdlog](https://github.com/gabime/spdlog) | [MIT License](https://spdx.org/licenses/MIT.html) |

@ -1 +1 @@
Subproject commit e12c4d6be450a163b38548f72e72f4080fc71dbb
Subproject commit fbb06ff53e74d3a81b434b84fff1a5dfe4b2d3c7

View file

@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.20)
set(PROJECT_NAME scwx-mbgl)
set(gtest_disable_pthreads ON)
set(MBGL_WITH_QT ON)
set(MBGL_QT_WITH_INTERNAL_ICU ON)
set(MLN_WITH_QT ON)
set(MLN_QT_WITH_INTERNAL_ICU ON)
add_subdirectory(mapbox-gl-native)
find_package(ZLIB)

View file

@ -78,6 +78,7 @@ set(HDR_MAP source/scwx/qt/map/alert_layer.hpp
source/scwx/qt/map/generic_layer.hpp
source/scwx/qt/map/layer_wrapper.hpp
source/scwx/qt/map/map_context.hpp
source/scwx/qt/map/map_provider.hpp
source/scwx/qt/map/map_settings.hpp
source/scwx/qt/map/map_widget.hpp
source/scwx/qt/map/overlay_layer.hpp
@ -89,6 +90,7 @@ set(SRC_MAP source/scwx/qt/map/alert_layer.cpp
source/scwx/qt/map/generic_layer.cpp
source/scwx/qt/map/layer_wrapper.cpp
source/scwx/qt/map/map_context.cpp
source/scwx/qt/map/map_provider.cpp
source/scwx/qt/map/map_widget.cpp
source/scwx/qt/map/overlay_layer.cpp
source/scwx/qt/map/radar_product_layer.cpp

View file

@ -58,12 +58,14 @@ void DrawItem::UseDefaultProjection(
static glm::vec2
LatLongToScreenCoordinate(const QMapLibreGL::Coordinate& coordinate)
{
static constexpr double RAD2DEG_D = 180.0 / M_PI;
double latitude = std::clamp(
coordinate.first, -mbgl::util::LATITUDE_MAX, mbgl::util::LATITUDE_MAX);
glm::vec2 screen {
mbgl::util::LONGITUDE_MAX + coordinate.second,
-(mbgl::util::LONGITUDE_MAX -
mbgl::util::RAD2DEG_D *
RAD2DEG_D *
std::log(std::tan(M_PI / 4.0 +
latitude * M_PI / mbgl::util::DEGREES_MAX)))};
return screen;

View file

@ -9,6 +9,7 @@
#include <scwx/qt/manager/settings_manager.hpp>
#include <scwx/qt/manager/text_event_manager.hpp>
#include <scwx/qt/manager/update_manager.hpp>
#include <scwx/qt/map/map_provider.hpp>
#include <scwx/qt/map/map_widget.hpp>
#include <scwx/qt/model/radar_product_model.hpp>
#include <scwx/qt/ui/alert_dock_widget.hpp>
@ -74,10 +75,18 @@ public:
elevationButtonsChanged_ {false},
resizeElevationButtons_ {false}
{
mapProvider_ =
map::GetMapProvider(manager::SettingsManager::general_settings()
.map_provider()
.GetValue());
const map::MapProviderInfo& mapProviderInfo =
map::GetMapProviderInfo(mapProvider_);
std::string appDataPath {
QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)
.toStdString()};
std::string cacheDbPath {appDataPath + "/mbgl-cache.db"};
std::string cacheDbPath {appDataPath + "/" +
mapProviderInfo.cacheDbName_};
if (!std::filesystem::exists(appDataPath))
{
@ -89,12 +98,10 @@ public:
}
}
std::string mapboxApiKey = manager::SettingsManager::general_settings()
.mapbox_api_key()
.GetValue();
std::string mapProviderApiKey = map::GetMapProviderApiKey(mapProvider_);
settings_.resetToTemplate(QMapLibreGL::Settings::MapboxSettings);
settings_.setApiKey(QString {mapboxApiKey.c_str()});
settings_.resetToTemplate(mapProviderInfo.settingsTemplate_);
settings_.setApiKey(QString {mapProviderApiKey.c_str()});
settings_.setCacheDatabasePath(QString {cacheDbPath.c_str()});
settings_.setCacheDatabaseMaximumSize(20 * 1024 * 1024);
}
@ -105,6 +112,7 @@ public:
void ConnectMapSignals();
void ConnectOtherSignals();
void HandleFocusChange(QWidget* focused);
void PopulateMapStyles();
void SelectElevation(map::MapWidget* mapWidget, float elevation);
void SelectRadarProduct(map::MapWidget* mapWidget,
common::RadarProductGroup group,
@ -113,6 +121,7 @@ public:
void SetActiveMap(map::MapWidget* mapWidget);
void UpdateAvailableLevel3Products();
void UpdateElevationSelection(float elevation);
void UpdateMapStyle(const std::string& styleName);
void UpdateRadarProductSelection(common::RadarProductGroup group,
const std::string& product);
void UpdateRadarProductSettings();
@ -121,6 +130,7 @@ public:
MainWindow* mainWindow_;
QMapLibreGL::Settings settings_;
map::MapProvider mapProvider_;
map::MapWidget* activeMap_;
ui::Level2ProductsWidget* level2ProductsWidget_;
@ -245,6 +255,7 @@ MainWindow::MainWindow(QWidget* parent) :
0);
}
p->PopulateMapStyles();
p->ConnectMapSignals();
p->ConnectOtherSignals();
p->HandleFocusChange(p->activeMap_);
@ -586,6 +597,11 @@ void MainWindowImpl::ConnectMapSignals()
},
Qt::QueuedConnection);
connect(mapWidget,
&map::MapWidget::MapStyleChanged,
this,
&MainWindowImpl::UpdateMapStyle);
connect(
mapWidget,
&map::MapWidget::RadarSweepUpdated,
@ -624,6 +640,11 @@ void MainWindowImpl::ConnectOtherSignals()
&QApplication::focusChanged,
mainWindow_,
[this](QWidget* /*old*/, QWidget* now) { HandleFocusChange(now); });
connect(mainWindow_->ui->mapStyleComboBox,
&QComboBox::currentTextChanged,
mainWindow_,
[&](const QString& text)
{ activeMap_->SetMapStyle(text.toStdString()); });
connect(level2ProductsWidget_,
&ui::Level2ProductsWidget::RadarProductSelected,
mainWindow_,
@ -696,6 +717,7 @@ void MainWindowImpl::HandleFocusChange(QWidget* focused)
{
SetActiveMap(mapWidget);
UpdateAvailableLevel3Products();
UpdateMapStyle(mapWidget->GetMapStyle());
UpdateRadarProductSelection(mapWidget->GetRadarProductGroup(),
mapWidget->GetRadarProductName());
UpdateRadarProductSettings();
@ -704,6 +726,16 @@ void MainWindowImpl::HandleFocusChange(QWidget* focused)
}
}
void MainWindowImpl::PopulateMapStyles()
{
const auto& mapProviderInfo = map::GetMapProviderInfo(mapProvider_);
for (const auto& mapStyle : mapProviderInfo.mapStyles_)
{
mainWindow_->ui->mapStyleComboBox->addItem(
QString::fromStdString(mapStyle.name_));
}
}
void MainWindowImpl::SelectElevation(map::MapWidget* mapWidget, float elevation)
{
if (mapWidget == activeMap_)
@ -767,6 +799,16 @@ void MainWindowImpl::UpdateMapParameters(
}
}
void MainWindowImpl::UpdateMapStyle(const std::string& styleName)
{
int index = mainWindow_->ui->mapStyleComboBox->findText(
QString::fromStdString(styleName));
if (index != -1)
{
mainWindow_->ui->mapStyleComboBox->setCurrentIndex(index);
}
}
void MainWindowImpl::UpdateRadarProductSelection(
common::RadarProductGroup group, const std::string& product)
{

View file

@ -184,6 +184,25 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="mapSettingsGroupBox">
<property name="title">
<string>Map Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="mapStyleLabel">
<property name="text">
<string>Map Style</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mapStyleComboBox"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="radarProductGroupBox">
<property name="title">

View file

@ -1,10 +1,12 @@
#include <scwx/qt/manager/settings_manager.hpp>
#include <scwx/qt/map/map_provider.hpp>
#include <scwx/qt/util/json.hpp>
#include <scwx/util/logger.hpp>
#include <filesystem>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <QDir>
#include <QStandardPaths>
@ -23,6 +25,7 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
static boost::json::value ConvertSettingsToJson();
static void GenerateDefaultSettings();
static bool LoadSettings(const boost::json::object& settingsJson);
static void ValidateSettings();
static bool initialized_ {false};
static std::string settingsPath_ {};
@ -46,6 +49,7 @@ void Initialize()
initialized_ = true;
ReadSettings(settingsPath_);
ValidateSettings();
}
void ReadSettings(const std::string& settingsPath)
@ -137,6 +141,47 @@ static bool LoadSettings(const boost::json::object& settingsJson)
return jsonDirty;
}
static void ValidateSettings()
{
logger_->debug("Validating settings");
bool settingsChanged = false;
auto& generalSettings = general_settings();
// Validate map provider
std::string mapProviderName = generalSettings.map_provider().GetValue();
std::string mapboxApiKey = generalSettings.mapbox_api_key().GetValue();
std::string maptilerApiKey = generalSettings.maptiler_api_key().GetValue();
map::MapProvider mapProvider = map::GetMapProvider(mapProviderName);
std::string mapApiKey = map::GetMapProviderApiKey(mapProvider);
if (mapApiKey == "?")
{
for (map::MapProvider newProvider : map::MapProviderIterator())
{
if (mapProvider != newProvider &&
map::GetMapProviderApiKey(newProvider).size() > 1)
{
logger_->info(
"Setting Map Provider to {} based on API key settings",
map::GetMapProviderName(newProvider));
std::string newProviderName {GetMapProviderName(newProvider)};
boost::to_lower(newProviderName);
generalSettings.map_provider().SetValue(newProviderName);
settingsChanged = true;
}
}
}
if (settingsChanged)
{
SaveSettings();
}
}
} // namespace SettingsManager
} // namespace manager
} // namespace qt

View file

@ -0,0 +1,127 @@
#include <scwx/qt/map/map_provider.hpp>
#include <scwx/qt/manager/settings_manager.hpp>
#include <unordered_map>
#include <boost/algorithm/string.hpp>
namespace scwx
{
namespace qt
{
namespace map
{
static const std::unordered_map<MapProvider, std::string> mapProviderName_ {
{MapProvider::Mapbox, "Mapbox"},
{MapProvider::MapTiler, "MapTiler"},
{MapProvider::Unknown, "?"}};
// Draw below tunnels, ferries and roads
static const std::vector<std::string> mapboxDrawBelow_ {
"tunnel.*", "ferry.*", "road.*"};
static const std::unordered_map<MapProvider, MapProviderInfo> mapProviderInfo_ {
{MapProvider::Mapbox,
MapProviderInfo {
.mapProvider_ {MapProvider::Mapbox},
.cacheDbName_ {"mbgl-cache.db"},
.settingsTemplate_ {
QMapLibreGL::Settings::SettingsTemplate::MapboxSettings},
.mapStyles_ {{.name_ {"Streets"},
.url_ {"mapbox://styles/mapbox/streets-v11"},
.drawBelow_ {mapboxDrawBelow_}},
{.name_ {"Outdoors"},
.url_ {"mapbox://styles/mapbox/outdoors-v11"},
.drawBelow_ {mapboxDrawBelow_}},
{.name_ {"Light"},
.url_ {"mapbox://styles/mapbox/light-v10"},
.drawBelow_ {mapboxDrawBelow_}},
{.name_ {"Dark"},
.url_ {"mapbox://styles/mapbox/dark-v10"},
.drawBelow_ {mapboxDrawBelow_}},
{.name_ {"Satellite"},
.url_ {"mapbox://styles/mapbox/satellite-v9"},
.drawBelow_ {mapboxDrawBelow_}},
{.name_ {"Satellite Streets"},
.url_ {"mapbox://styles/mapbox/satellite-streets-v11"},
.drawBelow_ {mapboxDrawBelow_}}}}},
{MapProvider::MapTiler,
MapProviderInfo {
.mapProvider_ {MapProvider::MapTiler},
.cacheDbName_ {"maptiler-cache.db"},
.settingsTemplate_ {
QMapLibreGL::Settings::SettingsTemplate::MapTilerSettings},
.mapStyles_ {{.name_ {"Satellite"},
.url_ {"maptiler://maps/hybrid"},
.drawBelow_ {"tunnel"}},
{.name_ {"Streets"},
.url_ {"maptiler://maps/streets-v2"},
.drawBelow_ {"aeroway"}},
{.name_ {"Basic"},
.url_ {"maptiler://maps/basic-v2"},
.drawBelow_ {"railway_transit_tunnel"}},
{.name_ {"Bright"},
.url_ {"maptiler://maps/bright-v2"},
.drawBelow_ {"ferry"}},
{.name_ {"Outdoor"},
.url_ {"maptiler://maps/outdoor-v2"},
.drawBelow_ {"aeroway_runway"}},
{.name_ {"Topo"},
.url_ {"maptiler://maps/topo-v2"},
.drawBelow_ {"aeroway_runway"}},
{.name_ {"Winter"},
.url_ {"maptiler://maps/winter-v2"},
.drawBelow_ {"aeroway_runway"}}}}},
{MapProvider::Unknown, MapProviderInfo {}}};
MapProvider GetMapProvider(const std::string& name)
{
auto result =
std::find_if(mapProviderName_.cbegin(),
mapProviderName_.cend(),
[&](const std::pair<MapProvider, std::string>& pair) -> bool
{ return boost::iequals(pair.second, name); });
if (result != mapProviderName_.cend())
{
return result->first;
}
else
{
return MapProvider::Unknown;
}
}
std::string GetMapProviderName(MapProvider mapProvider)
{
return mapProviderName_.at(mapProvider);
}
std::string GetMapProviderApiKey(MapProvider mapProvider)
{
switch (mapProvider)
{
case MapProvider::Mapbox:
return manager::SettingsManager::general_settings()
.mapbox_api_key()
.GetValue();
case MapProvider::MapTiler:
return manager::SettingsManager::general_settings()
.maptiler_api_key()
.GetValue();
default:
return "?";
}
}
const MapProviderInfo& GetMapProviderInfo(MapProvider mapProvider)
{
return mapProviderInfo_.at(mapProvider);
}
} // namespace map
} // namespace qt
} // namespace scwx

View file

@ -0,0 +1,48 @@
#pragma once
#include <scwx/util/iterator.hpp>
#include <string>
#include <QMapLibreGL/settings.hpp>
namespace scwx
{
namespace qt
{
namespace map
{
enum class MapProvider
{
Mapbox,
MapTiler,
Unknown
};
typedef scwx::util::
Iterator<MapProvider, MapProvider::Mapbox, MapProvider::MapTiler>
MapProviderIterator;
struct MapStyle
{
std::string name_;
std::string url_;
std::vector<std::string> drawBelow_;
};
struct MapProviderInfo
{
MapProvider mapProvider_ {MapProvider::Unknown};
std::string cacheDbName_ {};
QMapLibreGL::Settings::SettingsTemplate settingsTemplate_ {};
std::vector<MapStyle> mapStyles_ {};
};
MapProvider GetMapProvider(const std::string& name);
std::string GetMapProviderName(MapProvider mapProvider);
std::string GetMapProviderApiKey(MapProvider mapProvider);
const MapProviderInfo& GetMapProviderInfo(MapProvider mapProvider);
} // namespace map
} // namespace qt
} // namespace scwx

View file

@ -5,6 +5,7 @@
#include <scwx/qt/map/alert_layer.hpp>
#include <scwx/qt/map/color_table_layer.hpp>
#include <scwx/qt/map/layer_wrapper.hpp>
#include <scwx/qt/map/map_provider.hpp>
#include <scwx/qt/map/overlay_layer.hpp>
#include <scwx/qt/map/radar_product_layer.hpp>
#include <scwx/qt/map/radar_range_layer.hpp>
@ -15,6 +16,8 @@
#include <scwx/util/threads.hpp>
#include <scwx/util/time.hpp>
#include <regex>
#include <backends/imgui_impl_opengl3.h>
#include <backends/imgui_impl_qt.hpp>
#include <boost/uuid/random_generator.hpp>
@ -39,20 +42,6 @@ namespace map
static const std::string logPrefix_ = "scwx::qt::map::map_widget";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
typedef std::pair<std::string, std::string> MapStyle;
// clang-format off
static const MapStyle streets { "mapbox://styles/mapbox/streets-v11", "Streets"};
static const MapStyle outdoors { "mapbox://styles/mapbox/outdoors-v11", "Outdoors"};
static const MapStyle light { "mapbox://styles/mapbox/light-v10", "Light"};
static const MapStyle dark { "mapbox://styles/mapbox/dark-v10", "Dark" };
static const MapStyle satellite { "mapbox://styles/mapbox/satellite-v9", "Satellite" };
static const MapStyle satelliteStreets { "mapbox://styles/mapbox/satellite-streets-v11", "Satellite Streets" };
// clang-format on
static const std::array<MapStyle, 6> mapboxStyles_ = {
{streets, outdoors, light, dark, satellite, satelliteStreets}};
class MapWidgetImpl : public QObject
{
Q_OBJECT
@ -77,6 +66,7 @@ public:
selectedTime_ {},
lastPos_(),
currentStyleIndex_ {0},
currentStyle_ {nullptr},
frameDraws_(0),
prevLatitude_ {0.0},
prevLongitude_ {0.0},
@ -84,9 +74,10 @@ public:
prevBearing_ {0.0},
prevPitch_ {0.0}
{
SetRadarSite(scwx::qt::manager::SettingsManager::general_settings()
.default_radar_site()
.GetValue());
auto& generalSettings =
scwx::qt::manager::SettingsManager::general_settings();
SetRadarSite(generalSettings.default_radar_site().GetValue());
// Create ImGui Context
static size_t currentMapId_ {0u};
@ -97,6 +88,9 @@ public:
// Initialize ImGui Qt backend
ImGui_ImplQt_Init();
ImGui_ImplQt_RegisterWidget(widget_);
// Set Map Provider Details
mapProvider_ = GetMapProvider(generalSettings.map_provider().GetValue());
}
~MapWidgetImpl()
@ -134,6 +128,7 @@ public:
std::shared_ptr<MapContext> context_;
MapWidget* widget_;
MapProvider mapProvider_;
QMapLibreGL::Settings settings_;
std::shared_ptr<QMapLibreGL::Map> map_;
std::list<std::string> layerList_;
@ -156,8 +151,9 @@ public:
common::Level2Product selectedLevel2Product_;
std::chrono::system_clock::time_point selectedTime_;
QPointF lastPos_;
uint8_t currentStyleIndex_;
QPointF lastPos_;
std::size_t currentStyleIndex_;
const MapStyle* currentStyle_;
uint64_t frameDraws_;
@ -268,6 +264,18 @@ std::vector<std::string> MapWidget::GetLevel3Products()
}
}
std::string MapWidget::GetMapStyle() const
{
if (p->currentStyle_ != nullptr)
{
return p->currentStyle_->name_;
}
else
{
return "?";
}
}
common::RadarProductGroup MapWidget::GetRadarProductGroup() const
{
auto radarProductView = p->context_->radar_product_view();
@ -538,6 +546,32 @@ void MapWidget::SetMapParameters(
}
}
void MapWidget::SetMapStyle(const std::string& styleName)
{
const auto& mapProviderInfo = GetMapProviderInfo(p->mapProvider_);
auto& styles = mapProviderInfo.mapStyles_;
for (size_t i = 0u; i < styles.size(); ++i)
{
if (styles[i].name_ == styleName)
{
p->currentStyleIndex_ = i;
p->currentStyle_ = &styles[i];
logger_->debug("Updating style: {}", styles[i].name_);
p->map_->setStyleUrl(styles[i].url_.c_str());
if (++p->currentStyleIndex_ == styles.size())
{
p->currentStyleIndex_ = 0;
}
break;
}
}
}
qreal MapWidget::pixelRatio()
{
return devicePixelRatioF();
@ -545,16 +579,21 @@ qreal MapWidget::pixelRatio()
void MapWidget::changeStyle()
{
auto& styles = mapboxStyles_;
const auto& mapProviderInfo = GetMapProviderInfo(p->mapProvider_);
auto& styles = mapProviderInfo.mapStyles_;
p->map_->setStyleUrl(styles[p->currentStyleIndex_].first.c_str());
setWindowTitle(QString("Mapbox GL: ") +
styles[p->currentStyleIndex_].second.c_str());
p->currentStyle_ = &styles[p->currentStyleIndex_];
logger_->debug("Updating style: {}", styles[p->currentStyleIndex_].name_);
p->map_->setStyleUrl(styles[p->currentStyleIndex_].url_.c_str());
if (++p->currentStyleIndex_ == styles.size())
{
p->currentStyleIndex_ = 0;
}
emit MapStyleChanged(p->currentStyle_->name_);
}
void MapWidget::AddLayers()
@ -578,15 +617,26 @@ void MapWidget::AddLayers()
std::shared_ptr<config::RadarSite> radarSite =
p->radarProductManager_->radar_site();
const auto& mapStyle = *p->currentStyle_;
std::string before = "ferry";
for (const QString& layer : p->map_->layerIds())
for (const QString& qlayer : p->map_->layerIds())
{
// Draw below tunnels, ferries and roads
if (layer.startsWith("tunnel") || layer.startsWith("ferry") ||
layer.startsWith("road"))
const std::string layer = qlayer.toStdString();
// Draw below layers defined in map style
auto it = std::find_if(mapStyle.drawBelow_.cbegin(),
mapStyle.drawBelow_.cend(),
[&layer](const std::string& styleLayer) -> bool
{
std::regex re {styleLayer};
return std::regex_match(layer, re);
});
if (it != mapStyle.drawBelow_.cend())
{
before = layer.toStdString();
before = layer;
break;
}
}
@ -740,16 +790,8 @@ void MapWidget::initializeGL()
p->prevBearing_,
p->prevPitch_);
QString styleUrl = qgetenv("MAPBOX_STYLE_URL");
if (styleUrl.isEmpty())
{
changeStyle();
}
else
{
p->map_->setStyleUrl(styleUrl);
setWindowTitle(QString("Mapbox GL: ") + styleUrl);
}
// Update style
changeStyle();
connect(p->map_.get(),
&QMapLibreGL::Map::mapChanged,

View file

@ -38,6 +38,7 @@ public:
float GetElevation() const;
std::vector<float> GetElevationCuts() const;
std::vector<std::string> GetLevel3Products();
std::string GetMapStyle() const;
common::RadarProductGroup GetRadarProductGroup() const;
std::string GetRadarProductName() const;
std::shared_ptr<config::RadarSite> GetRadarSite() const;
@ -98,6 +99,7 @@ public:
double zoom,
double bearing,
double pitch);
void SetMapStyle(const std::string& styleName);
private:
void changeStyle();
@ -129,6 +131,7 @@ signals:
double zoom,
double bearing,
double pitch);
void MapStyleChanged(const std::string& styleName);
void RadarSweepUpdated();
};

View file

@ -359,12 +359,14 @@ void RadarProductLayer::UpdateColorTable()
static glm::vec2
LatLongToScreenCoordinate(const QMapLibreGL::Coordinate& coordinate)
{
static constexpr double RAD2DEG_D = 180.0 / M_PI;
double latitude = std::clamp(
coordinate.first, -mbgl::util::LATITUDE_MAX, mbgl::util::LATITUDE_MAX);
glm::vec2 screen {
mbgl::util::LONGITUDE_MAX + coordinate.second,
-(mbgl::util::LONGITUDE_MAX -
mbgl::util::RAD2DEG_D *
RAD2DEG_D *
std::log(std::tan(M_PI / 4.0 +
latitude * M_PI / mbgl::util::DEGREES_MAX)))};
return screen;

View file

@ -1,5 +1,10 @@
#include <scwx/qt/settings/general_settings.hpp>
#include <scwx/qt/settings/settings_container.hpp>
#include <scwx/qt/map/map_provider.hpp>
#include <array>
#include <boost/algorithm/string.hpp>
namespace scwx
{
@ -20,7 +25,9 @@ public:
fontSizes_.SetDefault({16});
gridWidth_.SetDefault(1);
gridHeight_.SetDefault(1);
mapProvider_.SetDefault("maptiler");
mapboxApiKey_.SetDefault("?");
maptilerApiKey_.SetDefault("?");
updateNotificationsEnabled_.SetDefault(true);
fontSizes_.SetElementMinimum(1);
@ -31,8 +38,29 @@ public:
gridWidth_.SetMaximum(2);
gridHeight_.SetMinimum(1);
gridHeight_.SetMaximum(2);
mapProvider_.SetValidator(
[](const std::string& value)
{
for (map::MapProvider mapProvider : map::MapProviderIterator())
{
// If the value is equal to a lower case map provider name
std::string mapProviderName =
map::GetMapProviderName(mapProvider);
boost::to_lower(mapProviderName);
if (value == mapProviderName)
{
// Regard as a match, valid
return true;
}
}
// No match found, invalid
return false;
});
mapboxApiKey_.SetValidator([](const std::string& value)
{ return !value.empty(); });
maptilerApiKey_.SetValidator([](const std::string& value)
{ return !value.empty(); });
}
~GeneralSettingsImpl() {}
@ -42,7 +70,9 @@ public:
SettingsContainer<std::vector<std::int64_t>> fontSizes_ {"font_sizes"};
SettingsVariable<std::int64_t> gridWidth_ {"grid_width"};
SettingsVariable<std::int64_t> gridHeight_ {"grid_height"};
SettingsVariable<std::string> mapProvider_ {"map_provider"};
SettingsVariable<std::string> mapboxApiKey_ {"mapbox_api_key"};
SettingsVariable<std::string> maptilerApiKey_ {"maptiler_api_key"};
SettingsVariable<bool> updateNotificationsEnabled_ {"update_notifications"};
};
@ -54,7 +84,9 @@ GeneralSettings::GeneralSettings() :
&p->fontSizes_,
&p->gridWidth_,
&p->gridHeight_,
&p->mapProvider_,
&p->mapboxApiKey_,
&p->maptilerApiKey_,
&p->updateNotificationsEnabled_});
SetDefaults();
}
@ -90,11 +122,21 @@ SettingsVariable<std::int64_t>& GeneralSettings::grid_width() const
return p->gridWidth_;
}
SettingsVariable<std::string>& GeneralSettings::map_provider() const
{
return p->mapProvider_;
}
SettingsVariable<std::string>& GeneralSettings::mapbox_api_key() const
{
return p->mapboxApiKey_;
}
SettingsVariable<std::string>& GeneralSettings::maptiler_api_key() const
{
return p->maptilerApiKey_;
}
SettingsVariable<bool>& GeneralSettings::update_notifications_enabled() const
{
return p->updateNotificationsEnabled_;
@ -107,7 +149,9 @@ bool operator==(const GeneralSettings& lhs, const GeneralSettings& rhs)
lhs.p->fontSizes_ == rhs.p->fontSizes_ &&
lhs.p->gridWidth_ == rhs.p->gridWidth_ &&
lhs.p->gridHeight_ == rhs.p->gridHeight_ &&
lhs.p->mapProvider_ == rhs.p->mapProvider_ &&
lhs.p->mapboxApiKey_ == rhs.p->mapboxApiKey_ &&
lhs.p->maptilerApiKey_ == rhs.p->maptilerApiKey_ &&
lhs.p->updateNotificationsEnabled_ ==
rhs.p->updateNotificationsEnabled_);
}

View file

@ -32,7 +32,9 @@ public:
SettingsContainer<std::vector<std::int64_t>>& font_sizes() const;
SettingsVariable<std::int64_t>& grid_height() const;
SettingsVariable<std::int64_t>& grid_width() const;
SettingsVariable<std::string>& map_provider() const;
SettingsVariable<std::string>& mapbox_api_key() const;
SettingsVariable<std::string>& maptiler_api_key() const;
SettingsVariable<bool>& update_notifications_enabled() const;
friend bool operator==(const GeneralSettings& lhs,

View file

@ -5,6 +5,7 @@
#include <scwx/common/color_table.hpp>
#include <scwx/qt/config/radar_site.hpp>
#include <scwx/qt/manager/settings_manager.hpp>
#include <scwx/qt/map/map_provider.hpp>
#include <scwx/qt/settings/settings_interface.hpp>
#include <scwx/qt/ui/radar_site_dialog.hpp>
#include <scwx/qt/util/color.hpp>
@ -12,6 +13,7 @@
#include <scwx/util/logger.hpp>
#include <scwx/util/threads.hpp>
#include <boost/algorithm/string.hpp>
#include <fmt/format.h>
#include <QColorDialog>
#include <QFileDialog>
@ -83,7 +85,9 @@ public:
&fontSizes_,
&gridWidth_,
&gridHeight_,
&mapProvider_,
&mapboxApiKey_,
&mapTilerApiKey_,
&updateNotificationsEnabled_,
&debugEnabled_}}
{
@ -137,7 +141,9 @@ public:
settings::SettingsInterface<std::vector<std::int64_t>> fontSizes_ {};
settings::SettingsInterface<std::int64_t> gridWidth_ {};
settings::SettingsInterface<std::int64_t> gridHeight_ {};
settings::SettingsInterface<std::string> mapProvider_ {};
settings::SettingsInterface<std::string> mapboxApiKey_ {};
settings::SettingsInterface<std::string> mapTilerApiKey_ {};
settings::SettingsInterface<bool> updateNotificationsEnabled_ {};
settings::SettingsInterface<bool> debugEnabled_ {};
@ -313,10 +319,46 @@ void SettingsDialogImpl::SetupGeneralTab()
gridHeight_.SetEditWidget(self_->ui->gridHeightSpinBox);
gridHeight_.SetResetButton(self_->ui->resetGridHeightButton);
for (const auto& mapProvider : map::MapProviderIterator())
{
self_->ui->mapProviderComboBox->addItem(
QString::fromStdString(map::GetMapProviderName(mapProvider)));
}
mapProvider_.SetSettingsVariable(generalSettings.map_provider());
mapProvider_.SetMapFromValueFunction(
[](const std::string& text) -> std::string
{
for (map::MapProvider mapProvider : map::MapProviderIterator())
{
if (boost::iequals(text, map::GetMapProviderName(mapProvider)))
{
// Return map provider label
return GetMapProviderName(mapProvider);
}
}
// Map provider label not found, return unknown
return "?";
});
mapProvider_.SetMapToValueFunction(
[](std::string text) -> std::string
{
// Convert label to lower case and return
boost::to_lower(text);
return text;
});
mapProvider_.SetEditWidget(self_->ui->mapProviderComboBox);
mapProvider_.SetResetButton(self_->ui->resetMapProviderButton);
mapboxApiKey_.SetSettingsVariable(generalSettings.mapbox_api_key());
mapboxApiKey_.SetEditWidget(self_->ui->mapboxApiKeyLineEdit);
mapboxApiKey_.SetResetButton(self_->ui->resetMapboxApiKeyButton);
mapTilerApiKey_.SetSettingsVariable(generalSettings.maptiler_api_key());
mapTilerApiKey_.SetEditWidget(self_->ui->mapTilerApiKeyLineEdit);
mapTilerApiKey_.SetResetButton(self_->ui->resetMapTilerApiKeyButton);
updateNotificationsEnabled_.SetSettingsVariable(
generalSettings.update_notifications_enabled());
updateNotificationsEnabled_.SetEditWidget(

View file

@ -109,43 +109,14 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Default Radar Site</string>
</property>
</widget>
<item row="1" column="2">
<widget class="QLineEdit" name="fontSizesLineEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Grid Height</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="gridHeightSpinBox"/>
</item>
<item row="2" column="4">
<widget class="QToolButton" name="resetGridWidthButton">
<item row="0" column="3">
<widget class="QToolButton" name="radarSiteSelectButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QToolButton" name="resetMapboxApiKeyButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
<item row="0" column="4">
@ -159,11 +130,41 @@
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QSpinBox" name="gridWidthSpinBox"/>
<item row="2" column="4">
<widget class="QToolButton" name="resetGridWidthButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="radarSiteComboBox"/>
<item row="6" column="4">
<widget class="QToolButton" name="resetMapTilerApiKeyButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Font Sizes</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>MapTiler API Key</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QToolButton" name="resetGridHeightButton">
@ -176,13 +177,13 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="fontSizesLineEdit"/>
<item row="2" column="2">
<widget class="QSpinBox" name="gridWidthSpinBox"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Mapbox API Key</string>
<string>Grid Height</string>
</property>
</widget>
</item>
@ -197,16 +198,36 @@
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLineEdit" name="mapboxApiKeyLineEdit"/>
<item row="6" column="2">
<widget class="QLineEdit" name="mapTilerApiKeyLineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<item row="0" column="2">
<widget class="QComboBox" name="radarSiteComboBox"/>
</item>
<item row="5" column="4">
<widget class="QToolButton" name="resetMapboxApiKeyButton">
<property name="text">
<string>Font Sizes</string>
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLineEdit" name="mapboxApiKeyLineEdit"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Mapbox API Key</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QSpinBox" name="gridHeightSpinBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
@ -214,11 +235,32 @@
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="radarSiteSelectButton">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Default Radar Site</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Map Provider</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QComboBox" name="mapProviderComboBox"/>
</item>
<item row="4" column="4">
<widget class="QToolButton" name="resetMapProviderButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../../../../scwx-qt.qrc">
<normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</normaloff>:/res/icons/font-awesome-6/rotate-left-solid.svg</iconset>
</property>
</widget>
</item>
</layout>

@ -1 +1 @@
Subproject commit 5b5073780fe44e55eb4c33799036683b28ffd2bd
Subproject commit 938b0240e51aff37530adc679a11d0e65e5e96ce