From d57d9c73daa89196eca78c91c10a37884e98acee Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 26 Feb 2024 22:18:22 -0600 Subject: [PATCH 01/33] Update dependency Qt to 6.6.2 --- .github/workflows/ci.yml | 4 ++-- setup-debug.bat | 2 +- setup-debug.sh | 2 +- setup-release.bat | 2 +- setup-release.sh | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b5d5af8..1a5237b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: compiler: msvc msvc_arch: x64 msvc_version: 2022 - qt_version: 6.6.1 + qt_version: 6.6.2 qt_arch: win64_msvc2019_64 qt_modules: qtimageformats qtmultimedia qtpositioning qt_tools: '' @@ -44,7 +44,7 @@ jobs: env_cc: gcc-11 env_cxx: g++-11 compiler: gcc - qt_version: 6.6.1 + qt_version: 6.6.2 qt_arch: gcc_64 qt_modules: qtimageformats qtmultimedia qtpositioning qt_tools: '' diff --git a/setup-debug.bat b/setup-debug.bat index ec5675df..85630abe 100644 --- a/setup-debug.bat +++ b/setup-debug.bat @@ -2,7 +2,7 @@ call tools\setup-common.bat set build_dir=build-debug set build_type=Debug -set qt_version=6.6.1 +set qt_version=6.6.2 mkdir %build_dir% cmake -B %build_dir% -S . ^ diff --git a/setup-debug.sh b/setup-debug.sh index f217020d..e5830ae0 100755 --- a/setup-debug.sh +++ b/setup-debug.sh @@ -3,7 +3,7 @@ build_dir=${1:-build-debug} build_type=Debug -qt_version=6.6.1 +qt_version=6.6.2 script_dir="$(dirname "$(readlink -f "$0")")" mkdir -p ${build_dir} diff --git a/setup-release.bat b/setup-release.bat index 7141c29b..1cfe114c 100644 --- a/setup-release.bat +++ b/setup-release.bat @@ -2,7 +2,7 @@ call tools\setup-common.bat set build_dir=build-release set build_type=Release -set qt_version=6.6.1 +set qt_version=6.6.2 mkdir %build_dir% cmake -B %build_dir% -S . ^ diff --git a/setup-release.sh b/setup-release.sh index 2c2cf0de..65943b6c 100755 --- a/setup-release.sh +++ b/setup-release.sh @@ -3,7 +3,7 @@ build_dir=${1:-build-release} build_type=Release -qt_version=6.6.1 +qt_version=6.6.2 script_dir="$(dirname "$(readlink -f "$0")")" mkdir -p ${build_dir} From 31ade020aceb650615a7e48512919c3d9358a923 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 27 Feb 2024 23:12:12 -0600 Subject: [PATCH 02/33] Add maplibre-native-qt dependency --- .gitmodules | 3 +++ external/maplibre-native-qt | 1 + 2 files changed, 4 insertions(+) create mode 160000 external/maplibre-native-qt diff --git a/.gitmodules b/.gitmodules index 8e51fe86..c05d6eb3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "external/textflowcpp"] path = external/textflowcpp url = https://github.com/catchorg/textflowcpp.git +[submodule "external/maplibre-native-qt"] + path = external/maplibre-native-qt + url = https://github.com/maplibre/maplibre-native-qt.git diff --git a/external/maplibre-native-qt b/external/maplibre-native-qt new file mode 160000 index 00000000..38dde09f --- /dev/null +++ b/external/maplibre-native-qt @@ -0,0 +1 @@ +Subproject commit 38dde09fee7a267b1762c87ad1eeeeeebb527e44 From db0d26a4adc2a27dba01a19bf58e828a632f4068 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 27 Feb 2024 23:13:08 -0600 Subject: [PATCH 03/33] Use maplibre-native-qt dependency instead of mapbox-gl-native --- CMakeLists.txt | 2 ++ external/CMakeLists.txt | 4 +-- external/maplibre-native-qt.cmake | 43 +++++++++++++++++++++++++++++++ scwx-qt/scwx-qt.cmake | 14 +++++----- 4 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 external/maplibre-native-qt.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 72d0499d..0889734f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,3 +48,5 @@ add_subdirectory(external) add_subdirectory(wxdata) add_subdirectory(scwx-qt) add_subdirectory(test) + +set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER CMakePredefinedTargets) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 8bbdf6da..bbc76c64 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -8,7 +8,7 @@ set_property(DIRECTORY date.cmake hsluv-c.cmake imgui.cmake - mapbox-gl-native.cmake + maplibre-native-qt.cmake stb.cmake textflowcpp.cmake units.cmake) @@ -17,7 +17,7 @@ include(aws-sdk-cpp.cmake) include(date.cmake) include(hsluv-c.cmake) include(imgui.cmake) -include(mapbox-gl-native.cmake) +include(maplibre-native-qt.cmake) include(stb.cmake) include(textflowcpp.cmake) include(units.cmake) diff --git a/external/maplibre-native-qt.cmake b/external/maplibre-native-qt.cmake new file mode 100644 index 00000000..aef6de7b --- /dev/null +++ b/external/maplibre-native-qt.cmake @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.20) +set(PROJECT_NAME scwx-mln) + +set(gtest_disable_pthreads ON) +set(MLN_WITH_QT ON) +set(MLN_QT_WITH_INTERNAL_ICU ON) +set(MLN_QT_WITH_LOCATION OFF) +add_subdirectory(maplibre-native-qt) + +find_package(ZLIB) +target_include_directories(mbgl-core PRIVATE ${ZLIB_INCLUDE_DIRS}) +target_link_libraries(mbgl-core INTERFACE ${ZLIB_LIBRARIES}) + +if (MSVC) + # Produce PDB file for debug + target_compile_options(mbgl-core PRIVATE "$<$:/Zi>") + target_compile_options(Core PRIVATE "$<$:/Zi>") + target_link_options(Core PRIVATE "$<$:/DEBUG>") + target_link_options(Core PRIVATE "$<$:/OPT:REF>") + target_link_options(Core PRIVATE "$<$:/OPT:ICF>") +else() + target_compile_options(mbgl-core PRIVATE "$<$:-g>") + target_compile_options(Core PRIVATE "$<$:-g>") +endif() + +set(MLN_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native-qt/vendor/maplibre-native/include + ${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native-qt/src/core/include + ${CMAKE_CURRENT_BINARY_DIR}/maplibre-native-qt/src/core/include PARENT_SCOPE) + +set_target_properties(test_mln_core PROPERTIES EXCLUDE_FROM_ALL True) +set_target_properties(test_mln_widgets PROPERTIES EXCLUDE_FROM_ALL True) +set_target_properties(Widgets PROPERTIES EXCLUDE_FROM_ALL True) + +set_target_properties(test_mln_core PROPERTIES FOLDER mln/exclude) +set_target_properties(test_mln_widgets PROPERTIES FOLDER mln/exclude) +set_target_properties(Widgets PROPERTIES FOLDER mln/exclude) + +set_target_properties(Core PROPERTIES FOLDER mln) +set_target_properties(mbgl-core PROPERTIES FOLDER mln) +set_target_properties(mbgl-vendor-csscolorparser PROPERTIES FOLDER mln) +set_target_properties(mbgl-vendor-nunicode PROPERTIES FOLDER mln) +set_target_properties(mbgl-vendor-parsedate PROPERTIES FOLDER mln) +set_target_properties(mbgl-vendor-sqlite PROPERTIES FOLDER mln) diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 53be9d97..d0121e40 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -496,7 +496,7 @@ endif() target_include_directories(scwx-qt PUBLIC ${scwx-qt_SOURCE_DIR}/source ${FTGL_INCLUDE_DIR} ${IMGUI_INCLUDE_DIRS} - ${MBGL_INCLUDE_DIR} + ${MLN_INCLUDE_DIRS} ${STB_INCLUDE_DIR} ${TEXTFLOWCPP_INCLUDE_DIR}) @@ -554,7 +554,7 @@ target_link_libraries(scwx-qt PUBLIC Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Positioning Boost::json Boost::timer - qmaplibregl + QMapLibre::Core $<$:opengl32> Fontconfig::Fontconfig GeographicLib::GeographicLib @@ -570,11 +570,11 @@ target_link_libraries(supercell-wx PRIVATE scwx-qt wxdata) # Set DT_RUNPATH for Linux targets -set_target_properties(qmaplibregl PROPERTIES INSTALL_RPATH "\$ORIGIN/../lib") +set_target_properties(Core PROPERTIES INSTALL_RPATH "\$ORIGIN/../lib") # QMapLibre::Core set_target_properties(supercell-wx PROPERTIES INSTALL_RPATH "\$ORIGIN/../lib") install(TARGETS supercell-wx - qmaplibregl + Core # QMapLibre::Core RUNTIME_DEPENDENCIES PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-" "qt6" POST_EXCLUDE_REGEXES ".*system32/.*\\.dll" @@ -587,8 +587,8 @@ install(TARGETS supercell-wx # NO_TRANSLATIONS is needed for Qt 6.5.0 (will be fixed in 6.5.1) # https://bugreports.qt.io/browse/QTBUG-112204 -qt_generate_deploy_app_script(TARGET qmaplibregl - OUTPUT_SCRIPT deploy_script_qmaplibregl +qt_generate_deploy_app_script(TARGET Core # QMapLibre::Core + OUTPUT_SCRIPT deploy_script_qmaplibre_core NO_TRANSLATIONS NO_UNSUPPORTED_PLATFORM_ERROR) @@ -597,7 +597,7 @@ qt_generate_deploy_app_script(TARGET supercell-wx NO_TRANSLATIONS NO_UNSUPPORTED_PLATFORM_ERROR) -install(SCRIPT ${deploy_script_qmaplibregl} +install(SCRIPT ${deploy_script_qmaplibre_core} COMPONENT supercell-wx) install(SCRIPT ${deploy_script_scwx} From 1fd52f771cf9e98b6e005b90a192dfa67a01bc65 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 27 Feb 2024 23:33:57 -0600 Subject: [PATCH 04/33] Refactor QMapLibreGL to QMapLibre --- scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp | 20 +++---- scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp | 24 ++++---- scwx-qt/source/scwx/qt/gl/draw/geo_icons.cpp | 4 +- scwx-qt/source/scwx/qt/gl/draw/geo_icons.hpp | 12 ++-- scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp | 4 +- scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp | 12 ++-- scwx-qt/source/scwx/qt/gl/draw/icons.cpp | 8 +-- scwx-qt/source/scwx/qt/gl/draw/icons.hpp | 12 ++-- .../source/scwx/qt/gl/draw/linked_vectors.cpp | 15 +++-- .../source/scwx/qt/gl/draw/linked_vectors.hpp | 12 ++-- .../scwx/qt/gl/draw/placefile_icons.cpp | 6 +- .../scwx/qt/gl/draw/placefile_icons.hpp | 12 ++-- .../scwx/qt/gl/draw/placefile_images.cpp | 4 +- .../scwx/qt/gl/draw/placefile_images.hpp | 2 +- .../scwx/qt/gl/draw/placefile_lines.cpp | 4 +- .../scwx/qt/gl/draw/placefile_lines.hpp | 12 ++-- .../scwx/qt/gl/draw/placefile_polygons.cpp | 2 +- .../scwx/qt/gl/draw/placefile_polygons.hpp | 2 +- .../source/scwx/qt/gl/draw/placefile_text.cpp | 33 ++++++----- .../source/scwx/qt/gl/draw/placefile_text.hpp | 12 ++-- .../scwx/qt/gl/draw/placefile_triangles.cpp | 2 +- .../scwx/qt/gl/draw/placefile_triangles.hpp | 2 +- scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp | 2 +- scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp | 2 +- scwx-qt/source/scwx/qt/main/main_window.cpp | 8 +-- .../scwx/qt/manager/radar_product_manager.cpp | 6 +- scwx-qt/source/scwx/qt/map/alert_layer.cpp | 56 +++++++++---------- .../source/scwx/qt/map/color_table_layer.cpp | 2 +- .../source/scwx/qt/map/color_table_layer.hpp | 2 +- scwx-qt/source/scwx/qt/map/draw_layer.cpp | 14 ++--- scwx-qt/source/scwx/qt/map/draw_layer.hpp | 13 ++--- scwx-qt/source/scwx/qt/map/generic_layer.cpp | 2 +- scwx-qt/source/scwx/qt/map/generic_layer.hpp | 20 +++---- scwx-qt/source/scwx/qt/map/layer_wrapper.cpp | 3 +- scwx-qt/source/scwx/qt/map/layer_wrapper.hpp | 4 +- scwx-qt/source/scwx/qt/map/map_context.cpp | 22 ++++---- scwx-qt/source/scwx/qt/map/map_context.hpp | 12 ++-- scwx-qt/source/scwx/qt/map/map_provider.cpp | 4 +- scwx-qt/source/scwx/qt/map/map_provider.hpp | 10 ++-- scwx-qt/source/scwx/qt/map/map_widget.cpp | 42 +++++++------- scwx-qt/source/scwx/qt/map/map_widget.hpp | 6 +- scwx-qt/source/scwx/qt/map/overlay_layer.cpp | 15 +++-- scwx-qt/source/scwx/qt/map/overlay_layer.hpp | 12 ++-- .../scwx/qt/map/overlay_product_layer.cpp | 14 ++--- .../scwx/qt/map/overlay_product_layer.hpp | 12 ++-- .../source/scwx/qt/map/placefile_layer.cpp | 2 +- .../source/scwx/qt/map/placefile_layer.hpp | 2 +- .../scwx/qt/map/radar_product_layer.cpp | 4 +- .../scwx/qt/map/radar_product_layer.hpp | 12 ++-- .../source/scwx/qt/map/radar_range_layer.cpp | 38 ++++++------- .../source/scwx/qt/map/radar_range_layer.hpp | 16 +++--- .../source/scwx/qt/map/radar_site_layer.cpp | 11 ++-- .../source/scwx/qt/map/radar_site_layer.hpp | 12 ++-- scwx-qt/source/scwx/qt/util/maplibre.cpp | 12 ++-- scwx-qt/source/scwx/qt/util/maplibre.hpp | 10 ++-- 55 files changed, 305 insertions(+), 313 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp b/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp index 861007c6..c6737a10 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/draw_item.cpp @@ -43,18 +43,18 @@ DrawItem::DrawItem(DrawItem&&) noexcept = default; DrawItem& DrawItem::operator=(DrawItem&&) noexcept = default; void DrawItem::Render( - const QMapLibreGL::CustomLayerRenderParameters& /* params */) + const QMapLibre::CustomLayerRenderParameters& /* params */) { } -void DrawItem::Render(const QMapLibreGL::CustomLayerRenderParameters& params, +void DrawItem::Render(const QMapLibre::CustomLayerRenderParameters& params, bool /* textureAtlasChanged */) { Render(params); } bool DrawItem::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& /* params */, + const QMapLibre::CustomLayerRenderParameters& /* params */, const QPointF& /* mouseLocalPos */, const QPointF& /* mouseGlobalPos */, const glm::vec2& /* mouseCoords */, @@ -66,8 +66,8 @@ bool DrawItem::RunMousePicking( } void DrawItem::UseDefaultProjection( - const QMapLibreGL::CustomLayerRenderParameters& params, - GLint uMVPMatrixLocation) + const QMapLibre::CustomLayerRenderParameters& params, + GLint uMVPMatrixLocation) { glm::mat4 projection = glm::ortho(0.0f, static_cast(params.width), @@ -79,8 +79,8 @@ void DrawItem::UseDefaultProjection( } void DrawItem::UseRotationProjection( - const QMapLibreGL::CustomLayerRenderParameters& params, - GLint uMVPMatrixLocation) + const QMapLibre::CustomLayerRenderParameters& params, + GLint uMVPMatrixLocation) { glm::mat4 projection = glm::ortho(0.0f, static_cast(params.width), @@ -96,9 +96,9 @@ void DrawItem::UseRotationProjection( } void DrawItem::UseMapProjection( - const QMapLibreGL::CustomLayerRenderParameters& params, - GLint uMVPMatrixLocation, - GLint uMapScreenCoordLocation) + const QMapLibre::CustomLayerRenderParameters& params, + GLint uMVPMatrixLocation, + GLint uMapScreenCoordLocation) { OpenGLFunctions& gl = p->gl_; diff --git a/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp b/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp index 809c5b1a..f7df44c4 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/draw_item.hpp @@ -6,8 +6,8 @@ #include -#include #include +#include namespace scwx { @@ -31,8 +31,8 @@ public: DrawItem& operator=(DrawItem&&) noexcept; virtual void Initialize() = 0; - virtual void Render(const QMapLibreGL::CustomLayerRenderParameters& params); - virtual void Render(const QMapLibreGL::CustomLayerRenderParameters& params, + virtual void Render(const QMapLibre::CustomLayerRenderParameters& params); + virtual void Render(const QMapLibre::CustomLayerRenderParameters& params, bool textureAtlasChanged); virtual void Deinitialize() = 0; @@ -49,21 +49,21 @@ public: * @return true if the draw item was picked, otherwise false */ virtual bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, - std::shared_ptr& eventHandler); + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, + std::shared_ptr& eventHandler); protected: void - UseDefaultProjection(const QMapLibreGL::CustomLayerRenderParameters& params, + UseDefaultProjection(const QMapLibre::CustomLayerRenderParameters& params, GLint uMVPMatrixLocation); void - UseRotationProjection(const QMapLibreGL::CustomLayerRenderParameters& params, + UseRotationProjection(const QMapLibre::CustomLayerRenderParameters& params, GLint uMVPMatrixLocation); - void UseMapProjection(const QMapLibreGL::CustomLayerRenderParameters& params, + void UseMapProjection(const QMapLibre::CustomLayerRenderParameters& params, GLint uMVPMatrixLocation, GLint uMapScreenCoordLocation); diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_icons.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_icons.cpp index 1f38d9c8..503960fb 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_icons.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_icons.cpp @@ -243,7 +243,7 @@ void GeoIcons::Initialize() p->dirty_ = true; } -void GeoIcons::Render(const QMapLibreGL::CustomLayerRenderParameters& params, +void GeoIcons::Render(const QMapLibre::CustomLayerRenderParameters& params, bool textureAtlasChanged) { if (!p->visible_) @@ -732,7 +732,7 @@ void GeoIcons::Impl::Update(bool textureAtlasChanged) } bool GeoIcons::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, + const QMapLibre::CustomLayerRenderParameters& params, const QPointF& /* mouseLocalPos */, const QPointF& mouseGlobalPos, const glm::vec2& mouseCoords, diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_icons.hpp b/scwx-qt/source/scwx/qt/gl/draw/geo_icons.hpp index f61443e1..455f4bd5 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_icons.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_icons.hpp @@ -33,16 +33,16 @@ public: void set_thresholded(bool thresholded); void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params, + void Render(const QMapLibre::CustomLayerRenderParameters& params, bool textureAtlasChanged) override; void Deinitialize() override; bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp index 32125039..0f9dd191 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.cpp @@ -218,7 +218,7 @@ void GeoLines::Initialize() p->dirty_ = true; } -void GeoLines::Render(const QMapLibreGL::CustomLayerRenderParameters& params) +void GeoLines::Render(const QMapLibre::CustomLayerRenderParameters& params) { if (!p->visible_) { @@ -513,7 +513,7 @@ void GeoLines::Impl::Update() } bool GeoLines::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, + const QMapLibre::CustomLayerRenderParameters& params, const QPointF& /* mouseLocalPos */, const QPointF& mouseGlobalPos, const glm::vec2& mouseCoords, diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp index e7564698..6422ab4a 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/geo_lines.hpp @@ -32,15 +32,15 @@ public: void set_thresholded(bool thresholded); void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; + void Render(const QMapLibre::CustomLayerRenderParameters& params) override; void Deinitialize() override; bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/icons.cpp b/scwx-qt/source/scwx/qt/gl/draw/icons.cpp index ec32bde0..86e7e542 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/icons.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/icons.cpp @@ -182,7 +182,7 @@ void Icons::Initialize() p->dirty_ = true; } -void Icons::Render(const QMapLibreGL::CustomLayerRenderParameters& params, +void Icons::Render(const QMapLibre::CustomLayerRenderParameters& params, bool textureAtlasChanged) { if (!p->visible_) @@ -575,9 +575,9 @@ void Icons::Impl::Update(bool textureAtlasChanged) } bool Icons::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, + const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, const glm::vec2& /* mouseCoords */, const common::Coordinate& /* mouseGeoCoords */, std::shared_ptr& eventHandler) diff --git a/scwx-qt/source/scwx/qt/gl/draw/icons.hpp b/scwx-qt/source/scwx/qt/gl/draw/icons.hpp index 081e22f1..d7207a11 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/icons.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/icons.hpp @@ -32,16 +32,16 @@ public: Icons& operator=(Icons&&) noexcept; void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params, + void Render(const QMapLibre::CustomLayerRenderParameters& params, bool textureAtlasChanged) override; void Deinitialize() override; bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.cpp b/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.cpp index 9e4b664f..be053e00 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.cpp @@ -103,8 +103,7 @@ void LinkedVectors::Initialize() p->geoLines_->Initialize(); } -void LinkedVectors::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) +void LinkedVectors::Render(const QMapLibre::CustomLayerRenderParameters& params) { if (!p->visible_) { @@ -337,12 +336,12 @@ void LinkedVectors::FinishVectors() } bool LinkedVectors::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, - std::shared_ptr& eventHandler) + const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, + std::shared_ptr& eventHandler) { return p->geoLines_->RunMousePicking(params, mouseLocalPos, diff --git a/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.hpp b/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.hpp index 9e8eef6c..06c0128d 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/linked_vectors.hpp @@ -43,15 +43,15 @@ public: void set_thresholded(bool thresholded); void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; + void Render(const QMapLibre::CustomLayerRenderParameters& params) override; void Deinitialize() override; bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.cpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.cpp index 1daddd9f..d343acf3 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.cpp @@ -255,8 +255,8 @@ void PlacefileIcons::Initialize() } void PlacefileIcons::Render( - const QMapLibreGL::CustomLayerRenderParameters& params, - bool textureAtlasChanged) + const QMapLibre::CustomLayerRenderParameters& params, + bool textureAtlasChanged) { std::unique_lock lock {p->iconMutex_}; @@ -685,7 +685,7 @@ void PlacefileIcons::Impl::Update(bool textureAtlasChanged) } bool PlacefileIcons::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, + const QMapLibre::CustomLayerRenderParameters& params, const QPointF& /* mouseLocalPos */, const QPointF& mouseGlobalPos, const glm::vec2& mouseCoords, diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.hpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.hpp index f34f5ffe..c70966e3 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_icons.hpp @@ -31,16 +31,16 @@ public: void set_thresholded(bool thresholded); void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params, + void Render(const QMapLibre::CustomLayerRenderParameters& params, bool textureAtlasChanged) override; void Deinitialize() override; bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_images.cpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_images.cpp index 1b46bd99..a1fbe032 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_images.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_images.cpp @@ -224,8 +224,8 @@ void PlacefileImages::Initialize() } void PlacefileImages::Render( - const QMapLibreGL::CustomLayerRenderParameters& params, - bool textureAtlasChanged) + const QMapLibre::CustomLayerRenderParameters& params, + bool textureAtlasChanged) { std::unique_lock lock {p->imageMutex_}; diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_images.hpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_images.hpp index d99c43a0..0603bb99 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_images.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_images.hpp @@ -29,7 +29,7 @@ public: void set_thresholded(bool thresholded); void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params, + void Render(const QMapLibre::CustomLayerRenderParameters& params, bool textureAtlasChanged) override; void Deinitialize() override; diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_lines.cpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_lines.cpp index f8815a22..ced0a41a 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_lines.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_lines.cpp @@ -213,7 +213,7 @@ void PlacefileLines::Initialize() } void PlacefileLines::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) + const QMapLibre::CustomLayerRenderParameters& params) { std::unique_lock lock {p->lineMutex_}; @@ -496,7 +496,7 @@ void PlacefileLines::Impl::Update() } bool PlacefileLines::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, + const QMapLibre::CustomLayerRenderParameters& params, const QPointF& /* mouseLocalPos */, const QPointF& mouseGlobalPos, const glm::vec2& mouseCoords, diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_lines.hpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_lines.hpp index 65ec03f0..c77c5bbd 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_lines.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_lines.hpp @@ -29,15 +29,15 @@ public: void set_thresholded(bool thresholded); void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; + void Render(const QMapLibre::CustomLayerRenderParameters& params) override; void Deinitialize() override; bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.cpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.cpp index 24a96fe6..2944fa20 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.cpp @@ -221,7 +221,7 @@ void PlacefilePolygons::Initialize() } void PlacefilePolygons::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) + const QMapLibre::CustomLayerRenderParameters& params) { if (!p->currentBuffer_.empty()) { diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.hpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.hpp index 3c607b72..873805c9 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_polygons.hpp @@ -31,7 +31,7 @@ public: void set_thresholded(bool thresholded); void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; + void Render(const QMapLibre::CustomLayerRenderParameters& params) override; void Deinitialize() override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_text.cpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_text.cpp index e996bdfc..b8faa8f8 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_text.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_text.cpp @@ -34,14 +34,14 @@ public: ~Impl() {} void RenderTextDrawItem( - const QMapLibreGL::CustomLayerRenderParameters& params, + const QMapLibre::CustomLayerRenderParameters& params, const std::shared_ptr& di); - void RenderText(const QMapLibreGL::CustomLayerRenderParameters& params, - const std::string& text, - const std::string& hoverText, - boost::gil::rgba8_pixel_t color, - float x, - float y); + void RenderText(const QMapLibre::CustomLayerRenderParameters& params, + const std::string& text, + const std::string& hoverText, + boost::gil::rgba8_pixel_t color, + float x, + float y); std::shared_ptr context_; @@ -98,8 +98,7 @@ void PlacefileText::set_thresholded(bool thresholded) void PlacefileText::Initialize() {} -void PlacefileText::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) +void PlacefileText::Render(const QMapLibre::CustomLayerRenderParameters& params) { std::unique_lock lock {p->listMutex_}; @@ -128,7 +127,7 @@ void PlacefileText::Render( } void PlacefileText::Impl::RenderTextDrawItem( - const QMapLibreGL::CustomLayerRenderParameters& params, + const QMapLibre::CustomLayerRenderParameters& params, const std::shared_ptr& di) { // If no time has been selected, use the current time @@ -191,12 +190,12 @@ void PlacefileText::Impl::RenderTextDrawItem( } void PlacefileText::Impl::RenderText( - const QMapLibreGL::CustomLayerRenderParameters& params, - const std::string& text, - const std::string& hoverText, - boost::gil::rgba8_pixel_t color, - float x, - float y) + const QMapLibre::CustomLayerRenderParameters& params, + const std::string& text, + const std::string& hoverText, + boost::gil::rgba8_pixel_t color, + float x, + float y) { const std::string windowName { fmt::format("PlacefileText-{}-{}", placefileName_, ++textId_)}; @@ -238,7 +237,7 @@ void PlacefileText::Deinitialize() } bool PlacefileText::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& /* params */, + const QMapLibre::CustomLayerRenderParameters& /* params */, const QPointF& /* mouseLocalPos */, const QPointF& mouseGlobalPos, const glm::vec2& /* mouseCoords */, diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_text.hpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_text.hpp index ee0ac0c8..4cbaf0af 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_text.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_text.hpp @@ -34,15 +34,15 @@ public: void set_thresholded(bool thresholded); void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; + void Render(const QMapLibre::CustomLayerRenderParameters& params) override; void Deinitialize() override; bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_triangles.cpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_triangles.cpp index dc0bc781..0b5f9c30 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_triangles.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_triangles.cpp @@ -169,7 +169,7 @@ void PlacefileTriangles::Initialize() } void PlacefileTriangles::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) + const QMapLibre::CustomLayerRenderParameters& params) { if (!p->currentBuffer_.empty()) { diff --git a/scwx-qt/source/scwx/qt/gl/draw/placefile_triangles.hpp b/scwx-qt/source/scwx/qt/gl/draw/placefile_triangles.hpp index daacc120..c5c8be0a 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/placefile_triangles.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/placefile_triangles.hpp @@ -29,7 +29,7 @@ public: void set_thresholded(bool thresholded); void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; + void Render(const QMapLibre::CustomLayerRenderParameters& params) override; void Deinitialize() override; /** diff --git a/scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp b/scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp index eebb333b..800e199f 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/rectangle.cpp @@ -122,7 +122,7 @@ void Rectangle::Initialize() p->dirty_ = true; } -void Rectangle::Render(const QMapLibreGL::CustomLayerRenderParameters& params) +void Rectangle::Render(const QMapLibre::CustomLayerRenderParameters& params) { if (p->visible_) { diff --git a/scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp b/scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp index 2c1cc69c..50a53281 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/rectangle.hpp @@ -27,7 +27,7 @@ public: Rectangle& operator=(Rectangle&&) noexcept; void Initialize() override; - void Render(const QMapLibreGL::CustomLayerRenderParameters& params) override; + void Render(const QMapLibre::CustomLayerRenderParameters& params) override; void Deinitialize() override; void SetBorder(float width, boost::gil::rgba8_pixel_t color); diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index 179c1020..3aa17d92 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -164,10 +164,10 @@ public: boost::asio::thread_pool threadPool_ {1u}; - MainWindow* mainWindow_; - QMapLibreGL::Settings settings_; - map::MapProvider mapProvider_; - map::MapWidget* activeMap_; + MainWindow* mainWindow_; + QMapLibre::Settings settings_; + map::MapProvider mapProvider_; + map::MapWidget* activeMap_; ui::CollapsibleGroup* mapSettingsGroup_; ui::CollapsibleGroup* level2ProductsGroup_; diff --git a/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp b/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp index 80fb4242..f79f1013 100644 --- a/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/radar_product_manager.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #if defined(_MSC_VER) # pragma warning(pop) @@ -423,8 +423,8 @@ void RadarProductManager::Initialize() const GeographicLib::Geodesic& geodesic( util::GeographicLib::DefaultGeodesic()); - const QMapLibreGL::Coordinate radar(p->radarSite_->latitude(), - p->radarSite_->longitude()); + const QMapLibre::Coordinate radar(p->radarSite_->latitude(), + p->radarSite_->longitude()); const float gateSize = gate_size(); diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.cpp b/scwx-qt/source/scwx/qt/map/alert_layer.cpp index d1676d7a..c7a8f1bd 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.cpp @@ -24,22 +24,22 @@ static const std::string logPrefix_ = "scwx::qt::map::alert_layer"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static std::vector -AddAlertLayer(std::shared_ptr map, - awips::Phenomenon phenomenon, - bool alertActive, - const QString& beforeLayer); -static QMapLibreGL::Feature +AddAlertLayer(std::shared_ptr map, + awips::Phenomenon phenomenon, + bool alertActive, + const QString& beforeLayer); +static QMapLibre::Feature CreateFeature(const awips::CodedLocation& codedLocation); -static QMapLibreGL::Coordinate +static QMapLibre::Coordinate GetMapboxCoordinate(const common::Coordinate& coordinate); -static QMapLibreGL::Coordinates +static QMapLibre::Coordinates GetMapboxCoordinates(const awips::CodedLocation& codedLocation); static QString GetSourceId(awips::Phenomenon phenomenon, bool alertActive); static QString GetSuffix(awips::Phenomenon phenomenon, bool alertActive); static const QVariantMap kEmptyFeatureCollection_ { {"type", "geojson"}, - {"data", QVariant::fromValue(std::list {})}}; + {"data", QVariant::fromValue(std::list {})}}; static const std::vector kAlertPhenomena_ { awips::Phenomenon::Marine, awips::Phenomenon::FlashFlood, @@ -87,8 +87,8 @@ class AlertLayerHandler : public QObject static std::shared_ptr Instance(); - std::list* FeatureList(awips::Phenomenon phenomenon, - bool alertActive); + std::list* FeatureList(awips::Phenomenon phenomenon, + bool alertActive); void HandleAlert(const types::TextEventKey& key, size_t messageIndex); void UpdateAlerts(); @@ -103,7 +103,7 @@ class AlertLayerHandler : public QObject std::unordered_multimap::iterator, + std::list::iterator, std::chrono::system_clock::time_point>, types::TextEventHash> featureMap_; @@ -166,16 +166,16 @@ std::vector AlertLayer::AddLayers(awips::Phenomenon phenomenon, return layers; } -std::list* +std::list* AlertLayerHandler::FeatureList(awips::Phenomenon phenomenon, bool alertActive) { - std::list* featureList = nullptr; + std::list* featureList = nullptr; auto key = std::make_pair(phenomenon, alertActive); auto it = alertSourceMap_.find(key); if (it != alertSourceMap_.cend()) { - featureList = reinterpret_cast*>( + featureList = reinterpret_cast*>( it->second["data"].data()); } @@ -371,10 +371,10 @@ std::shared_ptr AlertLayerHandler::Instance() } static std::vector -AddAlertLayer(std::shared_ptr map, - awips::Phenomenon phenomenon, - bool alertActive, - const QString& beforeLayer) +AddAlertLayer(std::shared_ptr map, + awips::Phenomenon phenomenon, + bool alertActive, + const QString& beforeLayer) { settings::PaletteSettings& paletteSettings = settings::PaletteSettings::Instance(); @@ -426,33 +426,33 @@ AddAlertLayer(std::shared_ptr map, return {bgLayerId.toStdString(), fgLayerId.toStdString()}; } -static QMapLibreGL::Feature +static QMapLibre::Feature CreateFeature(const awips::CodedLocation& codedLocation) { auto mapboxCoordinates = GetMapboxCoordinates(codedLocation); - return {QMapLibreGL::Feature::PolygonType, - std::initializer_list { - std::initializer_list { - {mapboxCoordinates}}}}; + return { + QMapLibre::Feature::PolygonType, + std::initializer_list { + std::initializer_list {{mapboxCoordinates}}}}; } -static QMapLibreGL::Coordinate +static QMapLibre::Coordinate GetMapboxCoordinate(const common::Coordinate& coordinate) { return {coordinate.latitude_, coordinate.longitude_}; } -static QMapLibreGL::Coordinates +static QMapLibre::Coordinates GetMapboxCoordinates(const awips::CodedLocation& codedLocation) { - auto scwxCoordinates = codedLocation.coordinates(); - QMapLibreGL::Coordinates mapboxCoordinates(scwxCoordinates.size() + 1u); + auto scwxCoordinates = codedLocation.coordinates(); + QMapLibre::Coordinates mapboxCoordinates(scwxCoordinates.size() + 1u); std::transform(scwxCoordinates.cbegin(), scwxCoordinates.cend(), mapboxCoordinates.begin(), - [](auto& coordinate) -> QMapLibreGL::Coordinate + [](auto& coordinate) -> QMapLibre::Coordinate { return GetMapboxCoordinate(coordinate); }); mapboxCoordinates.back() = GetMapboxCoordinate(scwxCoordinates.front()); diff --git a/scwx-qt/source/scwx/qt/map/color_table_layer.cpp b/scwx-qt/source/scwx/qt/map/color_table_layer.cpp index eb5d5d13..20d9c9dc 100644 --- a/scwx-qt/source/scwx/qt/map/color_table_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/color_table_layer.cpp @@ -116,7 +116,7 @@ void ColorTableLayer::Initialize() } void ColorTableLayer::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) + const QMapLibre::CustomLayerRenderParameters& params) { gl::OpenGLFunctions& gl = context()->gl(); auto radarProductView = context()->radar_product_view(); diff --git a/scwx-qt/source/scwx/qt/map/color_table_layer.hpp b/scwx-qt/source/scwx/qt/map/color_table_layer.hpp index 3fd8c07f..c23dc2b8 100644 --- a/scwx-qt/source/scwx/qt/map/color_table_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/color_table_layer.hpp @@ -18,7 +18,7 @@ public: ~ColorTableLayer(); void Initialize() override final; - void Render(const QMapLibreGL::CustomLayerRenderParameters&) override final; + void Render(const QMapLibre::CustomLayerRenderParameters&) override final; void Deinitialize() override final; private: diff --git a/scwx-qt/source/scwx/qt/map/draw_layer.cpp b/scwx-qt/source/scwx/qt/map/draw_layer.cpp index 5b0dd7ca..92254307 100644 --- a/scwx-qt/source/scwx/qt/map/draw_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/draw_layer.cpp @@ -44,7 +44,7 @@ void DrawLayer::Initialize() } } -void DrawLayer::Render(const QMapLibreGL::CustomLayerRenderParameters& params) +void DrawLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) { gl::OpenGLFunctions& gl = p->context_->gl(); p->textureAtlas_ = p->context_->GetTextureAtlas(); @@ -77,12 +77,12 @@ void DrawLayer::Deinitialize() } bool DrawLayer::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, - std::shared_ptr& eventHandler) + const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, + std::shared_ptr& eventHandler) { bool itemPicked = false; diff --git a/scwx-qt/source/scwx/qt/map/draw_layer.hpp b/scwx-qt/source/scwx/qt/map/draw_layer.hpp index adf71457..22dfa76c 100644 --- a/scwx-qt/source/scwx/qt/map/draw_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/draw_layer.hpp @@ -19,16 +19,15 @@ public: virtual ~DrawLayer(); virtual void Initialize() override; - virtual void - Render(const QMapLibreGL::CustomLayerRenderParameters&) override; + virtual void Render(const QMapLibre::CustomLayerRenderParameters&) override; virtual void Deinitialize() override; virtual bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override; protected: diff --git a/scwx-qt/source/scwx/qt/map/generic_layer.cpp b/scwx-qt/source/scwx/qt/map/generic_layer.cpp index d93345ae..97f22097 100644 --- a/scwx-qt/source/scwx/qt/map/generic_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/generic_layer.cpp @@ -27,7 +27,7 @@ GenericLayer::GenericLayer(std::shared_ptr context) : GenericLayer::~GenericLayer() = default; bool GenericLayer::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& /* params */, + const QMapLibre::CustomLayerRenderParameters& /* params */, const QPointF& /* mouseLocalPos */, const QPointF& /* mouseGlobalPos */, const glm::vec2& /* mousePos */, diff --git a/scwx-qt/source/scwx/qt/map/generic_layer.hpp b/scwx-qt/source/scwx/qt/map/generic_layer.hpp index 0ebc4869..0fee92ab 100644 --- a/scwx-qt/source/scwx/qt/map/generic_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/generic_layer.hpp @@ -7,8 +7,8 @@ #include #include -#include #include +#include namespace scwx { @@ -27,9 +27,9 @@ public: explicit GenericLayer(std::shared_ptr context); virtual ~GenericLayer(); - virtual void Initialize() = 0; - virtual void Render(const QMapLibreGL::CustomLayerRenderParameters&) = 0; - virtual void Deinitialize() = 0; + virtual void Initialize() = 0; + virtual void Render(const QMapLibre::CustomLayerRenderParameters&) = 0; + virtual void Deinitialize() = 0; /** * @brief Run mouse picking on the layer. @@ -44,12 +44,12 @@ public: * @return true if a draw item was picked, otherwise false */ virtual bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, - std::shared_ptr& eventHandler); + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, + std::shared_ptr& eventHandler); signals: void NeedsRendering(); diff --git a/scwx-qt/source/scwx/qt/map/layer_wrapper.cpp b/scwx-qt/source/scwx/qt/map/layer_wrapper.cpp index a7d47808..2e66f8d7 100644 --- a/scwx-qt/source/scwx/qt/map/layer_wrapper.cpp +++ b/scwx-qt/source/scwx/qt/map/layer_wrapper.cpp @@ -34,8 +34,7 @@ void LayerWrapper::initialize() p->layer_->Initialize(); } -void LayerWrapper::render( - const QMapLibreGL::CustomLayerRenderParameters& params) +void LayerWrapper::render(const QMapLibre::CustomLayerRenderParameters& params) { p->layer_->Render(params); } diff --git a/scwx-qt/source/scwx/qt/map/layer_wrapper.hpp b/scwx-qt/source/scwx/qt/map/layer_wrapper.hpp index 9e23c53e..6e0e44ee 100644 --- a/scwx-qt/source/scwx/qt/map/layer_wrapper.hpp +++ b/scwx-qt/source/scwx/qt/map/layer_wrapper.hpp @@ -11,7 +11,7 @@ namespace map class LayerWrapperImpl; -class LayerWrapper : public QMapLibreGL::CustomLayerHostInterface +class LayerWrapper : public QMapLibre::CustomLayerHostInterface { public: explicit LayerWrapper(std::shared_ptr layer); @@ -24,7 +24,7 @@ public: LayerWrapper& operator=(LayerWrapper&&) noexcept; void initialize() override final; - void render(const QMapLibreGL::CustomLayerRenderParameters&) override final; + void render(const QMapLibre::CustomLayerRenderParameters&) override final; void deinitialize() override final; private: diff --git a/scwx-qt/source/scwx/qt/map/map_context.cpp b/scwx-qt/source/scwx/qt/map/map_context.cpp index 7590d9d7..4dc87bb1 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.cpp +++ b/scwx-qt/source/scwx/qt/map/map_context.cpp @@ -20,14 +20,14 @@ public: ~Impl() {} - std::weak_ptr map_ {}; - MapSettings settings_ {}; - float pixelRatio_ {1.0f}; - common::RadarProductGroup radarProductGroup_ { + std::weak_ptr map_ {}; + MapSettings settings_ {}; + float pixelRatio_ {1.0f}; + common::RadarProductGroup radarProductGroup_ { common::RadarProductGroup::Unknown}; - std::string radarProduct_ {"???"}; - int16_t radarProductCode_ {0}; - QMapLibreGL::CustomLayerRenderParameters renderParameters_ {}; + std::string radarProduct_ {"???"}; + int16_t radarProductCode_ {0}; + QMapLibre::CustomLayerRenderParameters renderParameters_ {}; std::shared_ptr overlayProductView_ {nullptr}; std::shared_ptr radarProductView_; @@ -43,7 +43,7 @@ MapContext::~MapContext() = default; MapContext::MapContext(MapContext&&) noexcept = default; MapContext& MapContext::operator=(MapContext&&) noexcept = default; -std::weak_ptr MapContext::map() const +std::weak_ptr MapContext::map() const { return p->map_; } @@ -84,12 +84,12 @@ int16_t MapContext::radar_product_code() const return p->radarProductCode_; } -QMapLibreGL::CustomLayerRenderParameters MapContext::render_parameters() const +QMapLibre::CustomLayerRenderParameters MapContext::render_parameters() const { return p->renderParameters_; } -void MapContext::set_map(const std::shared_ptr& map) +void MapContext::set_map(const std::shared_ptr& map) { p->map_ = map; } @@ -128,7 +128,7 @@ void MapContext::set_radar_product_code(int16_t radarProductCode) } void MapContext::set_render_parameters( - const QMapLibreGL::CustomLayerRenderParameters& params) + const QMapLibre::CustomLayerRenderParameters& params) { p->renderParameters_ = params; } diff --git a/scwx-qt/source/scwx/qt/map/map_context.hpp b/scwx-qt/source/scwx/qt/map/map_context.hpp index 30498ab3..d6613ae0 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.hpp +++ b/scwx-qt/source/scwx/qt/map/map_context.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace scwx { @@ -35,7 +35,7 @@ public: MapContext(MapContext&&) noexcept; MapContext& operator=(MapContext&&) noexcept; - std::weak_ptr map() const; + std::weak_ptr map() const; MapSettings& settings(); float pixel_ratio() const; std::shared_ptr overlay_product_view() const; @@ -43,9 +43,9 @@ public: common::RadarProductGroup radar_product_group() const; std::string radar_product() const; int16_t radar_product_code() const; - QMapLibreGL::CustomLayerRenderParameters render_parameters() const; + QMapLibre::CustomLayerRenderParameters render_parameters() const; - void set_map(const std::shared_ptr& map); + void set_map(const std::shared_ptr& map); void set_overlay_product_view( const std::shared_ptr& overlayProductView); void set_pixel_ratio(float pixelRatio); @@ -54,8 +54,8 @@ public: void set_radar_product_group(common::RadarProductGroup radarProductGroup); void set_radar_product(const std::string& radarProduct); void set_radar_product_code(int16_t radarProductCode); - void set_render_parameters( - const QMapLibreGL::CustomLayerRenderParameters& params); + void + set_render_parameters(const QMapLibre::CustomLayerRenderParameters& params); private: class Impl; diff --git a/scwx-qt/source/scwx/qt/map/map_provider.cpp b/scwx-qt/source/scwx/qt/map/map_provider.cpp index df4bba08..b27870d7 100644 --- a/scwx-qt/source/scwx/qt/map/map_provider.cpp +++ b/scwx-qt/source/scwx/qt/map/map_provider.cpp @@ -27,7 +27,7 @@ static const std::unordered_map mapProviderInfo_ { .mapProvider_ {MapProvider::Mapbox}, .cacheDbName_ {"mbgl-cache.db"}, .settingsTemplate_ { - QMapLibreGL::Settings::SettingsTemplate::MapboxSettings}, + QMapLibre::Settings::SettingsTemplate::MapboxSettings}, .mapStyles_ {{.name_ {"Streets"}, .url_ {"mapbox://styles/mapbox/streets-v11"}, .drawBelow_ {mapboxDrawBelow_}}, @@ -51,7 +51,7 @@ static const std::unordered_map mapProviderInfo_ { .mapProvider_ {MapProvider::MapTiler}, .cacheDbName_ {"maptiler-cache.db"}, .settingsTemplate_ { - QMapLibreGL::Settings::SettingsTemplate::MapTilerSettings}, + QMapLibre::Settings::SettingsTemplate::MapTilerSettings}, .mapStyles_ { {.name_ {"Satellite"}, .url_ {"maptiler://maps/hybrid"}, diff --git a/scwx-qt/source/scwx/qt/map/map_provider.hpp b/scwx-qt/source/scwx/qt/map/map_provider.hpp index 7e6bb491..9b89f4d4 100644 --- a/scwx-qt/source/scwx/qt/map/map_provider.hpp +++ b/scwx-qt/source/scwx/qt/map/map_provider.hpp @@ -4,7 +4,7 @@ #include -#include +#include namespace scwx { @@ -32,10 +32,10 @@ struct MapStyle struct MapProviderInfo { - MapProvider mapProvider_ {MapProvider::Unknown}; - std::string cacheDbName_ {}; - QMapLibreGL::Settings::SettingsTemplate settingsTemplate_ {}; - std::vector mapStyles_ {}; + MapProvider mapProvider_ {MapProvider::Unknown}; + std::string cacheDbName_ {}; + QMapLibre::Settings::SettingsTemplate settingsTemplate_ {}; + std::vector mapStyles_ {}; }; MapProvider GetMapProvider(const std::string& name); diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 9d841215..11367bbe 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -60,9 +60,9 @@ class MapWidgetImpl : public QObject Q_OBJECT public: - explicit MapWidgetImpl(MapWidget* widget, - std::size_t id, - const QMapLibreGL::Settings& settings) : + explicit MapWidgetImpl(MapWidget* widget, + std::size_t id, + const QMapLibre::Settings& settings) : id_ {id}, uuid_ {boost::uuids::random_generator()()}, context_ {std::make_shared()}, @@ -169,11 +169,11 @@ public: std::shared_ptr context_; - MapWidget* widget_; - MapProvider mapProvider_; - QMapLibreGL::Settings settings_; - std::shared_ptr map_; - std::list layerList_; + MapWidget* widget_; + MapProvider mapProvider_; + QMapLibre::Settings settings_; + std::shared_ptr map_; + std::list layerList_; std::vector> genericLayers_ {}; @@ -229,7 +229,7 @@ public slots: void Update(); }; -MapWidget::MapWidget(std::size_t id, const QMapLibreGL::Settings& settings) : +MapWidget::MapWidget(std::size_t id, const QMapLibre::Settings& settings) : p(std::make_unique(this, id, settings)) { if (settings::GeneralSettings::Instance().anti_aliasing_enabled().GetValue()) @@ -246,7 +246,7 @@ MapWidget::MapWidget(std::size_t id, const QMapLibreGL::Settings& settings) : MapWidget::~MapWidget() { - // Make sure we have a valid context so we can delete the QMapLibreGL. + // Make sure we have a valid context so we can delete the QMapLibre. makeCurrent(); } @@ -987,8 +987,8 @@ void MapWidgetImpl::AddLayer(const std::string& id, std::shared_ptr layer, const std::string& before) { - // QMapLibreGL::addCustomLayer will take ownership of the std::unique_ptr - std::unique_ptr pHost = + // QMapLibre::addCustomLayer will take ownership of the std::unique_ptr + std::unique_ptr pHost = std::make_unique(layer); try @@ -1131,10 +1131,10 @@ void MapWidget::initializeGL() p->imGuiRendererInitialized_ = true; p->map_.reset( - new QMapLibreGL::Map(nullptr, p->settings_, size(), pixelRatio())); + new QMapLibre::Map(nullptr, p->settings_, size(), pixelRatio())); p->context_->set_map(p->map_); connect(p->map_.get(), - &QMapLibreGL::Map::needsRendering, + &QMapLibre::Map::needsRendering, p.get(), &MapWidgetImpl::Update); @@ -1160,10 +1160,8 @@ void MapWidget::initializeGL() SetMapStyle(p->initialStyleName_); } - connect(p->map_.get(), - &QMapLibreGL::Map::mapChanged, - this, - &MapWidget::mapChanged); + connect( + p->map_.get(), &QMapLibre::Map::mapChanged, this, &MapWidget::mapChanged); } void MapWidget::paintGL() @@ -1192,7 +1190,7 @@ void MapWidget::paintGL() // Update pixel ratio p->context_->set_pixel_ratio(pixelRatio()); - // Render QMapLibreGL Map + // Render QMapLibre Map p->map_->resize(size()); p->map_->setFramebufferObject(defaultFramebufferObject(), size() * pixelRatio()); @@ -1243,7 +1241,7 @@ void MapWidgetImpl::ImGuiCheckFonts() void MapWidgetImpl::RunMousePicking() { - const QMapLibreGL::CustomLayerRenderParameters params = + const QMapLibre::CustomLayerRenderParameters params = context_->render_parameters(); auto coordinate = map_->coordinateForPixel(lastPos_); @@ -1318,11 +1316,11 @@ void MapWidgetImpl::RunMousePicking() lastItemPicked_ = itemPicked; } -void MapWidget::mapChanged(QMapLibreGL::Map::MapChange mapChange) +void MapWidget::mapChanged(QMapLibre::Map::MapChange mapChange) { switch (mapChange) { - case QMapLibreGL::Map::MapChangeDidFinishLoadingStyle: + case QMapLibre::Map::MapChangeDidFinishLoadingStyle: p->UpdateLoadedStyle(); p->AddLayers(); break; diff --git a/scwx-qt/source/scwx/qt/map/map_widget.hpp b/scwx-qt/source/scwx/qt/map/map_widget.hpp index 007fd2f4..7776e1c9 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.hpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -33,7 +33,7 @@ class MapWidget : public QOpenGLWidget Q_OBJECT public: - explicit MapWidget(std::size_t id, const QMapLibreGL::Settings&); + explicit MapWidget(std::size_t id, const QMapLibre::Settings&); ~MapWidget(); void DumpLayerList() const; @@ -139,7 +139,7 @@ private: friend class MapWidgetImpl; private slots: - void mapChanged(QMapLibreGL::Map::MapChange); + void mapChanged(QMapLibre::Map::MapChange); signals: void Level3ProductsChanged(); diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp index 6f23d8dd..afd88b7f 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp @@ -204,8 +204,7 @@ void OverlayLayer::Initialize() }); } -void OverlayLayer::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) +void OverlayLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) { gl::OpenGLFunctions& gl = context()->gl(); auto radarProductView = context()->radar_product_view(); @@ -393,12 +392,12 @@ void OverlayLayer::Deinitialize() } bool OverlayLayer::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, - std::shared_ptr& eventHandler) + const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, + std::shared_ptr& eventHandler) { // If sweep time was picked, don't process additional items if (p->sweepTimePicked_) diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.hpp b/scwx-qt/source/scwx/qt/map/overlay_layer.hpp index a1ddae6f..411694b1 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.hpp @@ -18,15 +18,15 @@ public: ~OverlayLayer(); void Initialize() override final; - void Render(const QMapLibreGL::CustomLayerRenderParameters&) override final; + void Render(const QMapLibre::CustomLayerRenderParameters&) override final; void Deinitialize() override final; bool RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override final; public slots: diff --git a/scwx-qt/source/scwx/qt/map/overlay_product_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_product_layer.cpp index 3e5d09b6..c8312c7d 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_product_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_product_layer.cpp @@ -139,7 +139,7 @@ void OverlayProductLayer::Initialize() } void OverlayProductLayer::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) + const QMapLibre::CustomLayerRenderParameters& params) { gl::OpenGLFunctions& gl = context()->gl(); @@ -436,12 +436,12 @@ std::string OverlayProductLayer::Impl::BuildHoverText( } bool OverlayProductLayer::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, - std::shared_ptr& eventHandler) + const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, + std::shared_ptr& eventHandler) { return DrawLayer::RunMousePicking(params, mouseLocalPos, diff --git a/scwx-qt/source/scwx/qt/map/overlay_product_layer.hpp b/scwx-qt/source/scwx/qt/map/overlay_product_layer.hpp index 0b550697..8f65c2d6 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_product_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/overlay_product_layer.hpp @@ -16,15 +16,15 @@ public: ~OverlayProductLayer(); void Initialize() override final; - void Render(const QMapLibreGL::CustomLayerRenderParameters&) override final; + void Render(const QMapLibre::CustomLayerRenderParameters&) override final; void Deinitialize() override final; bool RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override final; private: diff --git a/scwx-qt/source/scwx/qt/map/placefile_layer.cpp b/scwx-qt/source/scwx/qt/map/placefile_layer.cpp index 3f6e5961..63eebff8 100644 --- a/scwx-qt/source/scwx/qt/map/placefile_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/placefile_layer.cpp @@ -124,7 +124,7 @@ void PlacefileLayer::Initialize() } void PlacefileLayer::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) + const QMapLibre::CustomLayerRenderParameters& params) { gl::OpenGLFunctions& gl = context()->gl(); diff --git a/scwx-qt/source/scwx/qt/map/placefile_layer.hpp b/scwx-qt/source/scwx/qt/map/placefile_layer.hpp index ec351510..981c3c12 100644 --- a/scwx-qt/source/scwx/qt/map/placefile_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/placefile_layer.hpp @@ -25,7 +25,7 @@ public: void set_placefile_name(const std::string& placefileName); void Initialize() override final; - void Render(const QMapLibreGL::CustomLayerRenderParameters&) override final; + void Render(const QMapLibre::CustomLayerRenderParameters&) override final; void Deinitialize() override final; void ReloadData(); diff --git a/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp b/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp index c4b9e45d..07881e75 100644 --- a/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/radar_product_layer.cpp @@ -261,7 +261,7 @@ void RadarProductLayer::UpdateSweep() } void RadarProductLayer::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) + const QMapLibre::CustomLayerRenderParameters& params) { gl::OpenGLFunctions& gl = context()->gl(); @@ -329,7 +329,7 @@ void RadarProductLayer::Deinitialize() } bool RadarProductLayer::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& /* params */, + const QMapLibre::CustomLayerRenderParameters& /* params */, const QPointF& /* mouseLocalPos */, const QPointF& mouseGlobalPos, const glm::vec2& /* mouseCoords */, diff --git a/scwx-qt/source/scwx/qt/map/radar_product_layer.hpp b/scwx-qt/source/scwx/qt/map/radar_product_layer.hpp index a081d842..1e53eba8 100644 --- a/scwx-qt/source/scwx/qt/map/radar_product_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/radar_product_layer.hpp @@ -18,15 +18,15 @@ public: ~RadarProductLayer(); void Initialize() override final; - void Render(const QMapLibreGL::CustomLayerRenderParameters&) override final; + void Render(const QMapLibre::CustomLayerRenderParameters&) override final; void Deinitialize() override final; virtual bool - RunMousePicking(const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + RunMousePicking(const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override; private: diff --git a/scwx-qt/source/scwx/qt/map/radar_range_layer.cpp b/scwx-qt/source/scwx/qt/map/radar_range_layer.cpp index a4738404..66ce5df7 100644 --- a/scwx-qt/source/scwx/qt/map/radar_range_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/radar_range_layer.cpp @@ -15,13 +15,13 @@ namespace map static const std::string logPrefix_ = "scwx::qt::map::radar_range_layer"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); -static std::shared_ptr -GetRangeCircle(float range, QMapLibreGL::Coordinate center); +static std::shared_ptr +GetRangeCircle(float range, QMapLibre::Coordinate center); -void RadarRangeLayer::Add(std::shared_ptr map, - float range, - QMapLibreGL::Coordinate center, - const QString& before) +void RadarRangeLayer::Add(std::shared_ptr map, + float range, + QMapLibre::Coordinate center, + const QString& before) { static const QString layerId = QString::fromStdString(types::GetLayerName( types::LayerType::Data, types::DataLayer::RadarRange)); @@ -37,7 +37,7 @@ void RadarRangeLayer::Add(std::shared_ptr map, map->removeSource("rangeCircleSource"); } - std::shared_ptr rangeCircle = + std::shared_ptr rangeCircle = GetRangeCircle(range, center); map->addSource( @@ -49,19 +49,19 @@ void RadarRangeLayer::Add(std::shared_ptr map, map->setPaintProperty(layerId, "line-color", "rgba(128, 128, 128, 128)"); } -void RadarRangeLayer::Update(std::shared_ptr map, - float range, - QMapLibreGL::Coordinate center) +void RadarRangeLayer::Update(std::shared_ptr map, + float range, + QMapLibre::Coordinate center) { - std::shared_ptr rangeCircle = + std::shared_ptr rangeCircle = GetRangeCircle(range, center); map->updateSource("rangeCircleSource", {{"data", QVariant::fromValue(*rangeCircle)}}); } -static std::shared_ptr -GetRangeCircle(float range, QMapLibreGL::Coordinate center) +static std::shared_ptr +GetRangeCircle(float range, QMapLibre::Coordinate center) { const GeographicLib::Geodesic& geodesic( util::GeographicLib::DefaultGeodesic()); @@ -71,7 +71,7 @@ GetRangeCircle(float range, QMapLibreGL::Coordinate center) float angle = -angleDeltaH; - QMapLibreGL::Coordinates geometry; + QMapLibre::Coordinates geometry; for (uint16_t azimuth = 0; azimuth <= 720; ++azimuth) { @@ -90,11 +90,11 @@ GetRangeCircle(float range, QMapLibreGL::Coordinate center) angle += angleDelta; } - std::shared_ptr rangeCircle = - std::make_shared( - QMapLibreGL::Feature::LineStringType, - std::initializer_list { - std::initializer_list {geometry}}); + std::shared_ptr rangeCircle = + std::make_shared( + QMapLibre::Feature::LineStringType, + std::initializer_list { + std::initializer_list {geometry}}); return rangeCircle; } diff --git a/scwx-qt/source/scwx/qt/map/radar_range_layer.hpp b/scwx-qt/source/scwx/qt/map/radar_range_layer.hpp index b900a9d2..d900f01e 100644 --- a/scwx-qt/source/scwx/qt/map/radar_range_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/radar_range_layer.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace scwx { @@ -11,13 +11,13 @@ namespace map namespace RadarRangeLayer { -void Add(std::shared_ptr map, - float range, - QMapLibreGL::Coordinate center, - const QString& before = QString()); -void Update(std::shared_ptr map, - float range, - QMapLibreGL::Coordinate center); +void Add(std::shared_ptr map, + float range, + QMapLibre::Coordinate center, + const QString& before = QString()); +void Update(std::shared_ptr map, + float range, + QMapLibre::Coordinate center); } // namespace RadarRangeLayer } // namespace map diff --git a/scwx-qt/source/scwx/qt/map/radar_site_layer.cpp b/scwx-qt/source/scwx/qt/map/radar_site_layer.cpp index c7348615..33486185 100644 --- a/scwx-qt/source/scwx/qt/map/radar_site_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/radar_site_layer.cpp @@ -6,7 +6,6 @@ #include #include -// #include #include #include @@ -26,7 +25,7 @@ public: explicit Impl(RadarSiteLayer* self) : self_ {self} {} ~Impl() = default; - void RenderRadarSite(const QMapLibreGL::CustomLayerRenderParameters& params, + void RenderRadarSite(const QMapLibre::CustomLayerRenderParameters& params, std::shared_ptr& radarSite); RadarSiteLayer* self_; @@ -58,7 +57,7 @@ void RadarSiteLayer::Initialize() } void RadarSiteLayer::Render( - const QMapLibreGL::CustomLayerRenderParameters& params) + const QMapLibre::CustomLayerRenderParameters& params) { gl::OpenGLFunctions& gl = context()->gl(); @@ -90,8 +89,8 @@ void RadarSiteLayer::Render( } void RadarSiteLayer::Impl::RenderRadarSite( - const QMapLibreGL::CustomLayerRenderParameters& params, - std::shared_ptr& radarSite) + const QMapLibre::CustomLayerRenderParameters& params, + std::shared_ptr& radarSite) { const std::string windowName = fmt::format("radar-site-{}", radarSite->id()); @@ -158,7 +157,7 @@ void RadarSiteLayer::Deinitialize() } bool RadarSiteLayer::RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& /* params */, + const QMapLibre::CustomLayerRenderParameters& /* params */, const QPointF& /* mouseLocalPos */, const QPointF& mouseGlobalPos, const glm::vec2& /* mouseCoords */, diff --git a/scwx-qt/source/scwx/qt/map/radar_site_layer.hpp b/scwx-qt/source/scwx/qt/map/radar_site_layer.hpp index 6cd75f42..f88786f4 100644 --- a/scwx-qt/source/scwx/qt/map/radar_site_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/radar_site_layer.hpp @@ -19,15 +19,15 @@ public: ~RadarSiteLayer(); void Initialize() override final; - void Render(const QMapLibreGL::CustomLayerRenderParameters&) override final; + void Render(const QMapLibre::CustomLayerRenderParameters&) override final; void Deinitialize() override final; bool RunMousePicking( - const QMapLibreGL::CustomLayerRenderParameters& params, - const QPointF& mouseLocalPos, - const QPointF& mouseGlobalPos, - const glm::vec2& mouseCoords, - const common::Coordinate& mouseGeoCoords, + const QMapLibre::CustomLayerRenderParameters& params, + const QPointF& mouseLocalPos, + const QPointF& mouseGlobalPos, + const glm::vec2& mouseCoords, + const common::Coordinate& mouseGeoCoords, std::shared_ptr& eventHandler) override final; signals: diff --git a/scwx-qt/source/scwx/qt/util/maplibre.cpp b/scwx-qt/source/scwx/qt/util/maplibre.cpp index 9cc092bb..7a7b9c00 100644 --- a/scwx-qt/source/scwx/qt/util/maplibre.cpp +++ b/scwx-qt/source/scwx/qt/util/maplibre.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include namespace scwx @@ -13,14 +13,14 @@ namespace maplibre { units::length::meters -GetMapDistance(const QMapLibreGL::CustomLayerRenderParameters& params) +GetMapDistance(const QMapLibre::CustomLayerRenderParameters& params) { return units::length::meters( - QMapLibreGL::metersPerPixelAtLatitude(params.latitude, params.zoom) * + QMapLibre::metersPerPixelAtLatitude(params.latitude, params.zoom) * (params.width + params.height) / 2.0); } -glm::mat4 GetMapMatrix(const QMapLibreGL::CustomLayerRenderParameters& params) +glm::mat4 GetMapMatrix(const QMapLibre::CustomLayerRenderParameters& params) { glm::vec2 scale = GetMapScale(params); @@ -33,7 +33,7 @@ glm::mat4 GetMapMatrix(const QMapLibreGL::CustomLayerRenderParameters& params) return mapMatrix; } -glm::vec2 GetMapScale(const QMapLibreGL::CustomLayerRenderParameters& params) +glm::vec2 GetMapScale(const QMapLibre::CustomLayerRenderParameters& params) { const float scale = std::pow(2.0, params.zoom) * 2.0f * mbgl::util::tileSize_D / mbgl::util::DEGREES_MAX; @@ -73,7 +73,7 @@ bool IsPointInPolygon(const std::vector& vertices, return inPolygon; } -glm::vec2 LatLongToScreenCoordinate(const QMapLibreGL::Coordinate& coordinate) +glm::vec2 LatLongToScreenCoordinate(const QMapLibre::Coordinate& coordinate) { static constexpr double RAD2DEG_D = 180.0 / M_PI; diff --git a/scwx-qt/source/scwx/qt/util/maplibre.hpp b/scwx-qt/source/scwx/qt/util/maplibre.hpp index 35989cbf..62fb9cb2 100644 --- a/scwx-qt/source/scwx/qt/util/maplibre.hpp +++ b/scwx-qt/source/scwx/qt/util/maplibre.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -14,9 +14,9 @@ namespace maplibre { units::length::meters -GetMapDistance(const QMapLibreGL::CustomLayerRenderParameters& params); -glm::mat4 GetMapMatrix(const QMapLibreGL::CustomLayerRenderParameters& params); -glm::vec2 GetMapScale(const QMapLibreGL::CustomLayerRenderParameters& params); + GetMapDistance(const QMapLibre::CustomLayerRenderParameters& params); +glm::mat4 GetMapMatrix(const QMapLibre::CustomLayerRenderParameters& params); +glm::vec2 GetMapScale(const QMapLibre::CustomLayerRenderParameters& params); /** * @brief Determine whether a point lies within a polygon @@ -29,7 +29,7 @@ glm::vec2 GetMapScale(const QMapLibreGL::CustomLayerRenderParameters& params); bool IsPointInPolygon(const std::vector& vertices, const glm::vec2& point); -glm::vec2 LatLongToScreenCoordinate(const QMapLibreGL::Coordinate& coordinate); +glm::vec2 LatLongToScreenCoordinate(const QMapLibre::Coordinate& coordinate); } // namespace maplibre } // namespace util From e23c6c2624ff595cd8e634a36b0fc8ef13c88c68 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 27 Feb 2024 23:46:34 -0600 Subject: [PATCH 05/33] Refactor SettingsTemplate to ProviderTemplate --- scwx-qt/source/scwx/qt/main/main_window.cpp | 2 +- scwx-qt/source/scwx/qt/map/map_provider.cpp | 8 ++++---- scwx-qt/source/scwx/qt/map/map_provider.hpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index 3aa17d92..d064488b 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -120,7 +120,7 @@ public: std::string mapProviderApiKey = map::GetMapProviderApiKey(mapProvider_); - settings_.resetToTemplate(mapProviderInfo.settingsTemplate_); + settings_.setProviderTemplate(mapProviderInfo.providerTemplate_); settings_.setApiKey(QString {mapProviderApiKey.c_str()}); settings_.setCacheDatabasePath(QString {cacheDbPath.c_str()}); settings_.setCacheDatabaseMaximumSize(20 * 1024 * 1024); diff --git a/scwx-qt/source/scwx/qt/map/map_provider.cpp b/scwx-qt/source/scwx/qt/map/map_provider.cpp index b27870d7..6517e49c 100644 --- a/scwx-qt/source/scwx/qt/map/map_provider.cpp +++ b/scwx-qt/source/scwx/qt/map/map_provider.cpp @@ -26,8 +26,8 @@ static const std::unordered_map mapProviderInfo_ { MapProviderInfo { .mapProvider_ {MapProvider::Mapbox}, .cacheDbName_ {"mbgl-cache.db"}, - .settingsTemplate_ { - QMapLibre::Settings::SettingsTemplate::MapboxSettings}, + .providerTemplate_ { + QMapLibre::Settings::ProviderTemplate::MapboxProvider}, .mapStyles_ {{.name_ {"Streets"}, .url_ {"mapbox://styles/mapbox/streets-v11"}, .drawBelow_ {mapboxDrawBelow_}}, @@ -50,8 +50,8 @@ static const std::unordered_map mapProviderInfo_ { MapProviderInfo { .mapProvider_ {MapProvider::MapTiler}, .cacheDbName_ {"maptiler-cache.db"}, - .settingsTemplate_ { - QMapLibre::Settings::SettingsTemplate::MapTilerSettings}, + .providerTemplate_ { + QMapLibre::Settings::ProviderTemplate::MapTilerProvider}, .mapStyles_ { {.name_ {"Satellite"}, .url_ {"maptiler://maps/hybrid"}, diff --git a/scwx-qt/source/scwx/qt/map/map_provider.hpp b/scwx-qt/source/scwx/qt/map/map_provider.hpp index 9b89f4d4..cec68e92 100644 --- a/scwx-qt/source/scwx/qt/map/map_provider.hpp +++ b/scwx-qt/source/scwx/qt/map/map_provider.hpp @@ -34,7 +34,7 @@ struct MapProviderInfo { MapProvider mapProvider_ {MapProvider::Unknown}; std::string cacheDbName_ {}; - QMapLibre::Settings::SettingsTemplate settingsTemplate_ {}; + QMapLibre::Settings::ProviderTemplate providerTemplate_ {}; std::vector mapStyles_ {}; }; From 16c2fae408d81ef91d77690e7c8c1a40067ef9ad Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 27 Feb 2024 23:47:10 -0600 Subject: [PATCH 06/33] QMapLibre test refactoring --- test/source/scwx/qt/map/map_provider.test.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/source/scwx/qt/map/map_provider.test.cpp b/test/source/scwx/qt/map/map_provider.test.cpp index 8b330de9..3a6a64a5 100644 --- a/test/source/scwx/qt/map/map_provider.test.cpp +++ b/test/source/scwx/qt/map/map_provider.test.cpp @@ -3,10 +3,10 @@ #include #include -#include #include #include +#include #include namespace scwx @@ -45,22 +45,22 @@ TEST_P(ByMapProviderTest, MapProviderLayers) // Configure map provider const MapProviderInfo& mapProviderInfo = GetMapProviderInfo(mapProvider); - // Configure QMapLibreGL - QMapLibreGL::Settings mapSettings {}; - mapSettings.resetToTemplate(mapProviderInfo.settingsTemplate_); + // Configure QMapLibre + QMapLibre::Settings mapSettings {}; + mapSettings.setProviderTemplate(mapProviderInfo.providerTemplate_); mapSettings.setApiKey(QString::fromStdString(apiKey)); - QMapLibreGL::Map map(nullptr, mapSettings, QSize(1, 1)); + QMapLibre::Map map(nullptr, mapSettings, QSize(1, 1)); application.processEvents(); // Connect style load completion signal QObject::connect( &map, - &QMapLibreGL::Map::mapChanged, - [&](QMapLibreGL::Map::MapChange mapChange) + &QMapLibre::Map::mapChanged, + [&](QMapLibre::Map::MapChange mapChange) { if (mapChange == - QMapLibreGL::Map::MapChange::MapChangeDidFinishLoadingStyle) + QMapLibre::Map::MapChange::MapChangeDidFinishLoadingStyle) { application.exit(); } From ef83c41c0fd64a6fb70e727ce4a5a8bb3a01b920 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 27 Feb 2024 23:52:06 -0600 Subject: [PATCH 07/33] Remove mapbox-gl-native --- .gitmodules | 3 --- external/mapbox-gl-native | 1 - external/mapbox-gl-native.cmake | 48 --------------------------------- 3 files changed, 52 deletions(-) delete mode 160000 external/mapbox-gl-native delete mode 100644 external/mapbox-gl-native.cmake diff --git a/.gitmodules b/.gitmodules index c05d6eb3..f1e7fbbd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "external/mapbox-gl-native"] - path = external/mapbox-gl-native - 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 diff --git a/external/mapbox-gl-native b/external/mapbox-gl-native deleted file mode 160000 index 3e85454f..00000000 --- a/external/mapbox-gl-native +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3e85454fe5e571e7b235131912bb867ef9d75c3c diff --git a/external/mapbox-gl-native.cmake b/external/mapbox-gl-native.cmake deleted file mode 100644 index 9d8f34bb..00000000 --- a/external/mapbox-gl-native.cmake +++ /dev/null @@ -1,48 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -set(PROJECT_NAME scwx-mbgl) - -set(gtest_disable_pthreads ON) -set(MLN_WITH_QT ON) -set(MLN_QT_WITH_INTERNAL_ICU ON) -add_subdirectory(mapbox-gl-native) - -find_package(ZLIB) -target_include_directories(mbgl-core PRIVATE ${ZLIB_INCLUDE_DIRS}) -target_link_libraries(mbgl-core INTERFACE ${ZLIB_LIBRARIES}) - -if (MSVC) - # Produce PDB file for debug - target_compile_options(mbgl-core PRIVATE "$<$:/Zi>") - target_compile_options(qmaplibregl PRIVATE "$<$:/Zi>") - target_link_options(qmaplibregl PRIVATE "$<$:/DEBUG>") - target_link_options(qmaplibregl PRIVATE "$<$:/OPT:REF>") - target_link_options(qmaplibregl PRIVATE "$<$:/OPT:ICF>") -else() - target_compile_options(mbgl-core PRIVATE "$<$:-g>") - target_compile_options(qmaplibregl PRIVATE "$<$:-g>") -endif() - -set(MBGL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/mapbox-gl-native/include - ${CMAKE_CURRENT_SOURCE_DIR}/mapbox-gl-native/platform/qt/include PARENT_SCOPE) - -set_target_properties(mbgl-qt PROPERTIES EXCLUDE_FROM_ALL True) -set_target_properties(mbgl-test-runner PROPERTIES EXCLUDE_FROM_ALL True) - -set_target_properties(mbgl-benchmark PROPERTIES FOLDER mbgl/exclude) -set_target_properties(mbgl-render-test PROPERTIES FOLDER mbgl/exclude) -set_target_properties(mbgl-test PROPERTIES FOLDER mbgl/exclude) -set_target_properties(mbgl-vendor-benchmark PROPERTIES FOLDER mbgl/exclude) -set_target_properties(mbgl-vendor-googletest PROPERTIES FOLDER mbgl/exclude) -set_target_properties(mbgl-core-license PROPERTIES FOLDER mbgl/exclude) -set_target_properties(mbgl-qt PROPERTIES FOLDER mbgl/exclude) -set_target_properties(mbgl-test-runner PROPERTIES FOLDER mbgl/exclude) - -if (TARGET mbgl-qt-docs) - set_target_properties(mbgl-qt-docs PROPERTIES FOLDER mbgl/exclude) -endif() - -set_target_properties(mbgl-core PROPERTIES FOLDER mbgl) -set_target_properties(mbgl-vendor-csscolorparser PROPERTIES FOLDER mbgl) -set_target_properties(mbgl-vendor-nunicode PROPERTIES FOLDER mbgl) -set_target_properties(mbgl-vendor-parsedate PROPERTIES FOLDER mbgl) -set_target_properties(qmaplibregl PROPERTIES FOLDER mbgl) From 21088a5ace9550e29005db0524ee9873d297f4e3 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 28 Feb 2024 00:07:09 -0600 Subject: [PATCH 08/33] QMapLibre feature and layer interface updates --- scwx-qt/source/scwx/qt/map/alert_layer.cpp | 10 +++++----- scwx-qt/source/scwx/qt/map/radar_range_layer.cpp | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.cpp b/scwx-qt/source/scwx/qt/map/alert_layer.cpp index c7a8f1bd..8c2e33b0 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.cpp @@ -401,16 +401,16 @@ AddAlertLayer(std::shared_ptr map, const float opacity = outlineColor[3] / 255.0f; - map->addLayer({{"id", bgLayerId}, {"type", "line"}, {"source", sourceId}}, - beforeLayer); + map->addLayer( + bgLayerId, {{"type", "line"}, {"source", sourceId}}, beforeLayer); map->setLayoutProperty(bgLayerId, "line-join", "round"); map->setLayoutProperty(bgLayerId, "line-cap", "round"); map->setPaintProperty(bgLayerId, "line-color", "rgba(0, 0, 0, 255)"); map->setPaintProperty(bgLayerId, "line-opacity", QString("%1").arg(opacity)); map->setPaintProperty(bgLayerId, "line-width", "5"); - map->addLayer({{"id", fgLayerId}, {"type", "line"}, {"source", sourceId}}, - beforeLayer); + map->addLayer( + fgLayerId, {{"type", "line"}, {"source", sourceId}}, beforeLayer); map->setLayoutProperty(fgLayerId, "line-join", "round"); map->setLayoutProperty(fgLayerId, "line-cap", "round"); map->setPaintProperty(fgLayerId, @@ -431,7 +431,7 @@ CreateFeature(const awips::CodedLocation& codedLocation) { auto mapboxCoordinates = GetMapboxCoordinates(codedLocation); - return { + return QMapLibre::Feature { QMapLibre::Feature::PolygonType, std::initializer_list { std::initializer_list {{mapboxCoordinates}}}}; diff --git a/scwx-qt/source/scwx/qt/map/radar_range_layer.cpp b/scwx-qt/source/scwx/qt/map/radar_range_layer.cpp index 66ce5df7..e660c266 100644 --- a/scwx-qt/source/scwx/qt/map/radar_range_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/radar_range_layer.cpp @@ -44,8 +44,7 @@ void RadarRangeLayer::Add(std::shared_ptr map, "rangeCircleSource", {{"type", "geojson"}, {"data", QVariant::fromValue(*rangeCircle)}}); map->addLayer( - {{"id", layerId}, {"type", "line"}, {"source", "rangeCircleSource"}}, - before); + layerId, {{"type", "line"}, {"source", "rangeCircleSource"}}, before); map->setPaintProperty(layerId, "line-color", "rgba(128, 128, 128, 128)"); } From a74fb22c88f98ceebba983918c8d6cb5775e1dc7 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 1 Mar 2024 23:59:34 -0600 Subject: [PATCH 09/33] Add additional Mapbox styles --- scwx-qt/source/scwx/qt/map/map_provider.cpp | 59 ++++++++++++++------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/map_provider.cpp b/scwx-qt/source/scwx/qt/map/map_provider.cpp index 6517e49c..8dbdc6ba 100644 --- a/scwx-qt/source/scwx/qt/map/map_provider.cpp +++ b/scwx-qt/source/scwx/qt/map/map_provider.cpp @@ -28,24 +28,47 @@ static const std::unordered_map mapProviderInfo_ { .cacheDbName_ {"mbgl-cache.db"}, .providerTemplate_ { QMapLibre::Settings::ProviderTemplate::MapboxProvider}, - .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_ {"com.mapbox.annotations.points"}}, - {.name_ {"Satellite Streets"}, - .url_ {"mapbox://styles/mapbox/satellite-streets-v11"}, - .drawBelow_ {mapboxDrawBelow_}}}}}, + .mapStyles_ { + {.name_ {"Streets"}, + .url_ {"mapbox://styles/mapbox/streets-v11"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Basic"}, + .url_ { + "mapbox://styles/mapbox-map-design/cl4whef7m000714pc44f3qaxs"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Basic Overcast"}, + .url_ { + "mapbox://styles/mapbox-map-design/cl4whev1w002w16s9mgoliotw"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Bubble"}, + .url_ { + "mapbox://styles/mapbox-map-design/cl4wxue5j000c14r17uqrjpqb"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Dark"}, + .url_ {"mapbox://styles/mapbox/dark-v10"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Light"}, + .url_ {"mapbox://styles/mapbox/light-v10"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Navigation Guidance Day"}, + .url_ {"mapbox://styles/mapbox/navigation-guidance-day-v4"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Navigation Guidance Night"}, + .url_ {"mapbox://styles/mapbox/navigation-guidance-night-v4"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Outdoors"}, + .url_ {"mapbox://styles/mapbox/outdoors-v11"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Satellite"}, + .url_ {"mapbox://styles/mapbox/satellite-v9"}, + .drawBelow_ {"com.mapbox.annotations.points"}}, + {.name_ {"Satellite Streets"}, + .url_ {"mapbox://styles/mapbox/satellite-streets-v11"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Standard Oil Company"}, + .url_ { + "mapbox://styles/mapbox-map-design/ckr0svm3922ki18qntevm857n"}, + .drawBelow_ {mapboxDrawBelow_}}}}}, {MapProvider::MapTiler, MapProviderInfo { .mapProvider_ {MapProvider::MapTiler}, From e0c11382501929934d0a507a29df272f30e2460c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 2 Mar 2024 00:10:21 -0600 Subject: [PATCH 10/33] With MapTiler, use https for style URLs - Eliminates issues with rewriting maptiler:// to incorrect URLs --- scwx-qt/source/scwx/qt/main/main_window.cpp | 7 +++-- scwx-qt/source/scwx/qt/map/map_provider.cpp | 33 +++++++++++---------- scwx-qt/source/scwx/qt/map/map_widget.cpp | 6 ++-- scwx-qt/source/scwx/qt/util/maplibre.cpp | 15 ++++++++++ scwx-qt/source/scwx/qt/util/maplibre.hpp | 7 +++++ 5 files changed, 49 insertions(+), 19 deletions(-) diff --git a/scwx-qt/source/scwx/qt/main/main_window.cpp b/scwx-qt/source/scwx/qt/main/main_window.cpp index d064488b..85cff2fe 100644 --- a/scwx-qt/source/scwx/qt/main/main_window.cpp +++ b/scwx-qt/source/scwx/qt/main/main_window.cpp @@ -120,8 +120,11 @@ public: std::string mapProviderApiKey = map::GetMapProviderApiKey(mapProvider_); - settings_.setProviderTemplate(mapProviderInfo.providerTemplate_); - settings_.setApiKey(QString {mapProviderApiKey.c_str()}); + if (mapProvider_ == map::MapProvider::Mapbox) + { + settings_.setProviderTemplate(mapProviderInfo.providerTemplate_); + settings_.setApiKey(QString {mapProviderApiKey.c_str()}); + } settings_.setCacheDatabasePath(QString {cacheDbPath.c_str()}); settings_.setCacheDatabaseMaximumSize(20 * 1024 * 1024); diff --git a/scwx-qt/source/scwx/qt/map/map_provider.cpp b/scwx-qt/source/scwx/qt/map/map_provider.cpp index 8dbdc6ba..14ffb2b5 100644 --- a/scwx-qt/source/scwx/qt/map/map_provider.cpp +++ b/scwx-qt/source/scwx/qt/map/map_provider.cpp @@ -77,49 +77,52 @@ static const std::unordered_map mapProviderInfo_ { QMapLibre::Settings::ProviderTemplate::MapTilerProvider}, .mapStyles_ { {.name_ {"Satellite"}, - .url_ {"maptiler://maps/hybrid"}, + .url_ {"https://api.maptiler.com/maps/hybrid/style.json"}, .drawBelow_ {"tunnel"}}, {.name_ {"Streets"}, - .url_ {"maptiler://maps/streets-v2"}, + .url_ {"https://api.maptiler.com/maps/streets-v2/style.json"}, .drawBelow_ {"aeroway"}}, {.name_ {"Streets Dark"}, - .url_ {"maptiler://maps/streets-v2-dark"}, + .url_ {"https://api.maptiler.com/maps/streets-v2-dark/style.json"}, .drawBelow_ {"aeroway"}}, {.name_ {"Basic"}, - .url_ {"maptiler://maps/basic-v2"}, + .url_ {"https://api.maptiler.com/maps/basic-v2/style.json"}, .drawBelow_ {"railway_transit_tunnel", "Transit tunnel"}}, {.name_ {"Bright"}, - .url_ {"maptiler://maps/bright-v2"}, + .url_ {"https://api.maptiler.com/maps/bright-v2/style.json"}, .drawBelow_ {"ferry"}}, {.name_ {"Dataviz"}, - .url_ {"maptiler://maps/dataviz"}, + .url_ {"https://api.maptiler.com/maps/dataviz/style.json"}, .drawBelow_ {"aeroway"}}, {.name_ {"Dataviz Dark"}, - .url_ {"maptiler://maps/dataviz-dark"}, + .url_ {"https://api.maptiler.com/maps/dataviz-dark/style.json"}, .drawBelow_ {"aeroway"}}, {.name_ {"Outdoor"}, - .url_ {"maptiler://maps/outdoor-v2"}, + .url_ {"https://api.maptiler.com/maps/outdoor-v2/style.json"}, .drawBelow_ {"aeroway_runway", "Aeroway"}}, {.name_ {"Swisstopo"}, - .url_ {"maptiler://maps/ch-swisstopo-lbm"}, + .url_ {"https://api.maptiler.com/maps/ch-swisstopo-lbm/style.json"}, .drawBelow_ {"pattern_landcover_vineyard", "Vineyard pattern"}}, {.name_ {"Swisstopo Dark"}, - .url_ {"maptiler://maps/ch-swisstopo-lbm-dark"}, + .url_ { + "https://api.maptiler.com/maps/ch-swisstopo-lbm-dark/style.json"}, .drawBelow_ {"pattern_landcover_vineyard", "Vineyard pattern"}}, {.name_ {"Swisstopo Grey"}, - .url_ {"maptiler://maps/ch-swisstopo-lbm-grey"}, + .url_ { + "https://api.maptiler.com/maps/ch-swisstopo-lbm-grey/style.json"}, .drawBelow_ {"pattern_landcover_vineyard", "Vineyard pattern"}}, {.name_ {"Swisstopo Vivid"}, - .url_ {"maptiler://maps/ch-swisstopo-lbm-vivid"}, + .url_ {"https://api.maptiler.com/maps/ch-swisstopo-lbm-vivid/" + "style.json"}, .drawBelow_ {"pattern_landcover_vineyard", "Vineyard pattern"}}, {.name_ {"Topo"}, - .url_ {"maptiler://maps/topo-v2"}, + .url_ {"https://api.maptiler.com/maps/topo-v2/style.json"}, .drawBelow_ {"aeroway_runway", "Runway"}}, {.name_ {"Topo Dark"}, - .url_ {"maptiler://maps/topo-v2-dark"}, + .url_ {"https://api.maptiler.com/maps/topo-v2-dark/style.json"}, .drawBelow_ {"aeroway_runway", "Runway"}}, {.name_ {"Winter"}, - .url_ {"maptiler://maps/winter-v2"}, + .url_ {"https://api.maptiler.com/maps/winter-v2/style.json"}, .drawBelow_ {"aeroway_runway", "Aeroway"}}}}}, {MapProvider::Unknown, MapProviderInfo {}}}; diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 11367bbe..3412e7c0 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -737,7 +737,8 @@ void MapWidget::SetMapStyle(const std::string& styleName) logger_->debug("Updating style: {}", styles[i].name_); - p->map_->setStyleUrl(styles[i].url_.c_str()); + util::maplibre::SetMapStyleUrl( + p->map_, p->mapProvider_, styles[i].url_); if (++p->currentStyleIndex_ == styles.size()) { @@ -763,7 +764,8 @@ void MapWidget::changeStyle() logger_->debug("Updating style: {}", styles[p->currentStyleIndex_].name_); - p->map_->setStyleUrl(styles[p->currentStyleIndex_].url_.c_str()); + util::maplibre::SetMapStyleUrl( + p->map_, p->mapProvider_, styles[p->currentStyleIndex_].url_); if (++p->currentStyleIndex_ == styles.size()) { diff --git a/scwx-qt/source/scwx/qt/util/maplibre.cpp b/scwx-qt/source/scwx/qt/util/maplibre.cpp index 7a7b9c00..0adff1ed 100644 --- a/scwx-qt/source/scwx/qt/util/maplibre.cpp +++ b/scwx-qt/source/scwx/qt/util/maplibre.cpp @@ -88,6 +88,21 @@ glm::vec2 LatLongToScreenCoordinate(const QMapLibre::Coordinate& coordinate) return screen; } +void SetMapStyleUrl(const std::shared_ptr& map, + map::MapProvider mapProvider, + const std::string& url) +{ + QString qUrl = QString::fromStdString(url); + + if (mapProvider == map::MapProvider::MapTiler) + { + qUrl.append("?key="); + qUrl.append(map::GetMapProviderApiKey(mapProvider)); + } + + map->setStyleUrl(qUrl); +} + } // namespace maplibre } // namespace util } // namespace qt diff --git a/scwx-qt/source/scwx/qt/util/maplibre.hpp b/scwx-qt/source/scwx/qt/util/maplibre.hpp index 62fb9cb2..619ba2ca 100644 --- a/scwx-qt/source/scwx/qt/util/maplibre.hpp +++ b/scwx-qt/source/scwx/qt/util/maplibre.hpp @@ -1,5 +1,8 @@ #pragma once +#include + +#include #include #include #include @@ -31,6 +34,10 @@ bool IsPointInPolygon(const std::vector& vertices, glm::vec2 LatLongToScreenCoordinate(const QMapLibre::Coordinate& coordinate); +void SetMapStyleUrl(const std::shared_ptr& map, + map::MapProvider mapProvider, + const std::string& url); + } // namespace maplibre } // namespace util } // namespace qt From 737b023c32759027e85338fa439ad442f325a9a7 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 2 Mar 2024 00:10:43 -0600 Subject: [PATCH 11/33] Add additional MapLibre styles --- scwx-qt/source/scwx/qt/map/map_provider.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scwx-qt/source/scwx/qt/map/map_provider.cpp b/scwx-qt/source/scwx/qt/map/map_provider.cpp index 14ffb2b5..c0d7f470 100644 --- a/scwx-qt/source/scwx/qt/map/map_provider.cpp +++ b/scwx-qt/source/scwx/qt/map/map_provider.cpp @@ -85,6 +85,9 @@ static const std::unordered_map mapProviderInfo_ { {.name_ {"Streets Dark"}, .url_ {"https://api.maptiler.com/maps/streets-v2-dark/style.json"}, .drawBelow_ {"aeroway"}}, + {.name_ {"Backdrop"}, + .url_ {"https://api.maptiler.com/maps/backdrop/style.json"}, + .drawBelow_ {"Aeroway"}}, {.name_ {"Basic"}, .url_ {"https://api.maptiler.com/maps/basic-v2/style.json"}, .drawBelow_ {"railway_transit_tunnel", "Transit tunnel"}}, @@ -97,6 +100,9 @@ static const std::unordered_map mapProviderInfo_ { {.name_ {"Dataviz Dark"}, .url_ {"https://api.maptiler.com/maps/dataviz-dark/style.json"}, .drawBelow_ {"aeroway"}}, + {.name_ {"Landscape"}, + .url_ {"https://api.maptiler.com/maps/landscape/style.json"}, + .drawBelow_ {"Runway"}}, {.name_ {"Outdoor"}, .url_ {"https://api.maptiler.com/maps/outdoor-v2/style.json"}, .drawBelow_ {"aeroway_runway", "Aeroway"}}, From 5efeeb1080f763be5abd911254b7ae7e1d1f84bb Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 2 Mar 2024 00:57:43 -0600 Subject: [PATCH 12/33] Add maplibre-native submodule for greater flexibility of versioning --- .gitmodules | 3 +++ external/maplibre-native | 1 + external/maplibre-native-qt.cmake | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) create mode 160000 external/maplibre-native diff --git a/.gitmodules b/.gitmodules index f1e7fbbd..adb166fa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ [submodule "external/maplibre-native-qt"] path = external/maplibre-native-qt url = https://github.com/maplibre/maplibre-native-qt.git +[submodule "external/maplibre-native"] + path = external/maplibre-native + url = https://github.com/maplibre/maplibre-native.git diff --git a/external/maplibre-native b/external/maplibre-native new file mode 160000 index 00000000..4fff8a5d --- /dev/null +++ b/external/maplibre-native @@ -0,0 +1 @@ +Subproject commit 4fff8a5d33852c7bc4c5d8c989092eb42769a71d diff --git a/external/maplibre-native-qt.cmake b/external/maplibre-native-qt.cmake index aef6de7b..aae9d40b 100644 --- a/external/maplibre-native-qt.cmake +++ b/external/maplibre-native-qt.cmake @@ -5,6 +5,7 @@ set(gtest_disable_pthreads ON) set(MLN_WITH_QT ON) set(MLN_QT_WITH_INTERNAL_ICU ON) set(MLN_QT_WITH_LOCATION OFF) +set(MLN_CORE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native) add_subdirectory(maplibre-native-qt) find_package(ZLIB) @@ -23,7 +24,7 @@ else() target_compile_options(Core PRIVATE "$<$:-g>") endif() -set(MLN_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native-qt/vendor/maplibre-native/include +set(MLN_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native/include ${CMAKE_CURRENT_SOURCE_DIR}/maplibre-native-qt/src/core/include ${CMAKE_CURRENT_BINARY_DIR}/maplibre-native-qt/src/core/include PARENT_SCOPE) From 6b00c55bacfa70cbeb380bb282383646fe18137a Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 2 Mar 2024 23:28:35 -0600 Subject: [PATCH 13/33] Add Roboto Flex as default attribution font --- ACKNOWLEDGEMENTS.md | 1 + scwx-qt/res/fonts/RobotoFlex-Regular.ttf | Bin 0 -> 88912 bytes scwx-qt/scwx-qt.qrc | 1 + .../source/scwx/qt/manager/resource_manager.cpp | 3 ++- .../source/scwx/qt/settings/text_settings.cpp | 10 +++++++--- scwx-qt/source/scwx/qt/types/font_types.hpp | 3 ++- scwx-qt/source/scwx/qt/types/text_types.cpp | 1 + scwx-qt/source/scwx/qt/types/text_types.hpp | 3 ++- 8 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 scwx-qt/res/fonts/RobotoFlex-Regular.ttf diff --git a/ACKNOWLEDGEMENTS.md b/ACKNOWLEDGEMENTS.md index 78706a70..4b5474f2 100644 --- a/ACKNOWLEDGEMENTS.md +++ b/ACKNOWLEDGEMENTS.md @@ -67,6 +67,7 @@ Supercell Wx uses assets from the following sources: | [Font Awesome Free](https://fontawesome.com/) | CC BY 4.0 License | | [Inconsolata](https://fonts.google.com/specimen/Inconsolata) | SIL Open Font License | | [NOAA's Weather and Climate Toolkit](https://www.ncdc.noaa.gov/wct/) | Public Domain | Default Color Tables | +| [Roboto Flex](https://fonts.google.com/specimen/Roboto+Flex) | SIL Open Font License | | [Supercell thunderstorm with dramatic clouds](https://www.shutterstock.com/image-photo/supercell-thunderstorm-dramatic-clouds-1354353521) | Shutterstock Standard License | Photo by John Sirlin Services diff --git a/scwx-qt/res/fonts/RobotoFlex-Regular.ttf b/scwx-qt/res/fonts/RobotoFlex-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6cf3b2a47c29c94a67afeb52baad364a315d2eb8 GIT binary patch literal 88912 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 literal 0 HcmV?d00001 diff --git a/scwx-qt/scwx-qt.qrc b/scwx-qt/scwx-qt.qrc index 91d6ab02..4bc8a324 100644 --- a/scwx-qt/scwx-qt.qrc +++ b/scwx-qt/scwx-qt.qrc @@ -18,6 +18,7 @@ res/fonts/din1451alt.ttf res/fonts/din1451alt_g.ttf res/fonts/Inconsolata-Regular.ttf + res/fonts/RobotoFlex-Regular.ttf res/icons/scwx-64.png res/icons/scwx-256.ico res/icons/scwx-256.png diff --git a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp index c9c40b6b..443d771b 100644 --- a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp @@ -28,7 +28,8 @@ static void LoadTextures(); static const std::vector> fontNames_ { {types::Font::din1451alt, ":/res/fonts/din1451alt.ttf"}, {types::Font::din1451alt_g, ":/res/fonts/din1451alt_g.ttf"}, - {types::Font::Inconsolata_Regular, ":/res/fonts/Inconsolata-Regular.ttf"}}; + {types::Font::Inconsolata_Regular, ":/res/fonts/Inconsolata-Regular.ttf"}, + {types::Font::RobotoFlex_Regular, ":/res/fonts/RobotoFlex-Regular.ttf"}}; void Initialize() { diff --git a/scwx-qt/source/scwx/qt/settings/text_settings.cpp b/scwx-qt/source/scwx/qt/settings/text_settings.cpp index d8181df9..49b97c59 100644 --- a/scwx-qt/source/scwx/qt/settings/text_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/text_settings.cpp @@ -15,19 +15,23 @@ static const std::string logPrefix_ = "scwx::qt::settings::text_settings"; static const std::string kAlteDIN1451Mittelscrhift_ { "Alte DIN 1451 Mittelschrift"}; static const std::string kInconsolata_ {"Inconsolata"}; +static const std::string kRobotoFlex_ {"Roboto Flex"}; static const std::string kRegular_ {"Regular"}; static const std::unordered_map kDefaultFontFamily_ { {types::FontCategory::Default, kAlteDIN1451Mittelscrhift_}, - {types::FontCategory::Tooltip, kInconsolata_}}; + {types::FontCategory::Tooltip, kInconsolata_}, + {types::FontCategory::Attribution, kRobotoFlex_}}; static const std::unordered_map kDefaultFontStyle_ {{types::FontCategory::Default, kRegular_}, - {types::FontCategory::Tooltip, kRegular_}}; + {types::FontCategory::Tooltip, kRegular_}, + {types::FontCategory::Attribution, kRegular_}}; static const std::unordered_map kDefaultFontPointSize_ {{types::FontCategory::Default, 12.0}, - {types::FontCategory::Tooltip, 10.5}}; + {types::FontCategory::Tooltip, 10.5}, + {types::FontCategory::Attribution, 9.0}}; class TextSettings::Impl { diff --git a/scwx-qt/source/scwx/qt/types/font_types.hpp b/scwx-qt/source/scwx/qt/types/font_types.hpp index 6fc8c506..1f2805f9 100644 --- a/scwx-qt/source/scwx/qt/types/font_types.hpp +++ b/scwx-qt/source/scwx/qt/types/font_types.hpp @@ -37,7 +37,8 @@ enum class Font { din1451alt, din1451alt_g, - Inconsolata_Regular + Inconsolata_Regular, + RobotoFlex_Regular }; } // namespace types diff --git a/scwx-qt/source/scwx/qt/types/text_types.cpp b/scwx-qt/source/scwx/qt/types/text_types.cpp index f994dab9..14595686 100644 --- a/scwx-qt/source/scwx/qt/types/text_types.cpp +++ b/scwx-qt/source/scwx/qt/types/text_types.cpp @@ -14,6 +14,7 @@ namespace types static const std::unordered_map fontCategoryName_ { {FontCategory::Default, "Default"}, {FontCategory::Tooltip, "Tooltip"}, + {FontCategory::Attribution, "Attribution"}, {FontCategory::Unknown, "?"}}; static const std::unordered_map tooltipMethodName_ { diff --git a/scwx-qt/source/scwx/qt/types/text_types.hpp b/scwx-qt/source/scwx/qt/types/text_types.hpp index 07c1ea00..6e09c4ac 100644 --- a/scwx-qt/source/scwx/qt/types/text_types.hpp +++ b/scwx-qt/source/scwx/qt/types/text_types.hpp @@ -15,10 +15,11 @@ enum class FontCategory { Default, Tooltip, + Attribution, Unknown }; typedef scwx::util:: - Iterator + Iterator FontCategoryIterator; enum class TooltipMethod From 5c7c7e6a19465a27bdf9fe132412f2bb5e180f6c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 2 Mar 2024 23:29:44 -0600 Subject: [PATCH 14/33] Add map copyrights and map provider to map context --- scwx-qt/source/scwx/qt/map/map_context.cpp | 23 ++++++++++ scwx-qt/source/scwx/qt/map/map_context.hpp | 5 +++ scwx-qt/source/scwx/qt/map/map_widget.cpp | 50 ++++++++++++++-------- scwx-qt/source/scwx/qt/util/maplibre.cpp | 13 ++++-- scwx-qt/source/scwx/qt/util/maplibre.hpp | 7 ++- 5 files changed, 73 insertions(+), 25 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/map_context.cpp b/scwx-qt/source/scwx/qt/map/map_context.cpp index 4dc87bb1..14a9c559 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.cpp +++ b/scwx-qt/source/scwx/qt/map/map_context.cpp @@ -29,6 +29,9 @@ public: int16_t radarProductCode_ {0}; QMapLibre::CustomLayerRenderParameters renderParameters_ {}; + MapProvider mapProvider_ {MapProvider::Unknown}; + std::string mapCopyrights_ {}; + std::shared_ptr overlayProductView_ {nullptr}; std::shared_ptr radarProductView_; }; @@ -48,6 +51,16 @@ std::weak_ptr MapContext::map() const return p->map_; } +std::string MapContext::map_copyrights() const +{ + return p->mapCopyrights_; +} + +MapProvider MapContext::map_provider() const +{ + return p->mapProvider_; +} + MapSettings& MapContext::settings() { return p->settings_; @@ -94,6 +107,16 @@ void MapContext::set_map(const std::shared_ptr& map) p->map_ = map; } +void MapContext::set_map_copyrights(const std::string& copyrights) +{ + p->mapCopyrights_ = copyrights; +} + +void MapContext::set_map_provider(MapProvider provider) +{ + p->mapProvider_ = provider; +} + void MapContext::set_overlay_product_view( const std::shared_ptr& overlayProductView) { diff --git a/scwx-qt/source/scwx/qt/map/map_context.hpp b/scwx-qt/source/scwx/qt/map/map_context.hpp index d6613ae0..367c1006 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.hpp +++ b/scwx-qt/source/scwx/qt/map/map_context.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -36,6 +37,8 @@ public: MapContext& operator=(MapContext&&) noexcept; std::weak_ptr map() const; + std::string map_copyrights() const; + MapProvider map_provider() const; MapSettings& settings(); float pixel_ratio() const; std::shared_ptr overlay_product_view() const; @@ -46,6 +49,8 @@ public: QMapLibre::CustomLayerRenderParameters render_parameters() const; void set_map(const std::shared_ptr& map); + void set_map_copyrights(const std::string& copyrights); + void set_map_provider(MapProvider provider); void set_overlay_product_view( const std::shared_ptr& overlayProductView); void set_pixel_ratio(float pixelRatio); diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 3412e7c0..90139d19 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -44,6 +44,7 @@ #include #include #include +#include namespace scwx { @@ -94,11 +95,13 @@ public: overlayProductView->SetAutoRefresh(autoRefreshEnabled_); overlayProductView->SetAutoUpdate(autoUpdateEnabled_); - // Initialize context - context_->set_overlay_product_view(overlayProductView); - auto& generalSettings = settings::GeneralSettings::Instance(); + // Initialize context + context_->set_map_provider( + GetMapProvider(generalSettings.map_provider().GetValue())); + context_->set_overlay_product_view(overlayProductView); + SetRadarSite(generalSettings.default_radar_site().GetValue()); // Create ImGui Context @@ -110,9 +113,6 @@ public: // Initialize ImGui Qt backend ImGui_ImplQt_Init(); - // Set Map Provider Details - mapProvider_ = GetMapProvider(generalSettings.map_provider().GetValue()); - ConnectSignals(); } @@ -143,6 +143,7 @@ public: void AddLayers(); void AddPlacefileLayer(const std::string& placefileName, const std::string& before); + void ConnectMapSignals(); void ConnectSignals(); void ImGuiCheckFonts(); void InitializeNewRadarProductView(const std::string& colorPalette); @@ -170,7 +171,6 @@ public: std::shared_ptr context_; MapWidget* widget_; - MapProvider mapProvider_; QMapLibre::Settings settings_; std::shared_ptr map_; std::list layerList_; @@ -250,6 +250,24 @@ MapWidget::~MapWidget() makeCurrent(); } +void MapWidgetImpl::ConnectMapSignals() +{ + connect(map_.get(), + &QMapLibre::Map::needsRendering, + this, + &MapWidgetImpl::Update); + connect(map_.get(), + &QMapLibre::Map::copyrightsChanged, + this, + [this](const QString& copyrightsHtml) + { + QTextDocument document {}; + document.setHtml(copyrightsHtml); + context_->set_map_copyrights( + document.toPlainText().toStdString()); + }); +} + void MapWidgetImpl::ConnectSignals() { connect(placefileManager_.get(), @@ -725,7 +743,8 @@ void MapWidget::SetInitialMapStyle(const std::string& styleName) void MapWidget::SetMapStyle(const std::string& styleName) { - const auto& mapProviderInfo = GetMapProviderInfo(p->mapProvider_); + const auto mapProvider = p->context_->map_provider(); + const auto& mapProviderInfo = GetMapProviderInfo(mapProvider); auto& styles = mapProviderInfo.mapStyles_; for (size_t i = 0u; i < styles.size(); ++i) @@ -737,8 +756,7 @@ void MapWidget::SetMapStyle(const std::string& styleName) logger_->debug("Updating style: {}", styles[i].name_); - util::maplibre::SetMapStyleUrl( - p->map_, p->mapProvider_, styles[i].url_); + util::maplibre::SetMapStyleUrl(p->context_, styles[i].url_); if (++p->currentStyleIndex_ == styles.size()) { @@ -757,15 +775,16 @@ qreal MapWidget::pixelRatio() void MapWidget::changeStyle() { - const auto& mapProviderInfo = GetMapProviderInfo(p->mapProvider_); + const auto mapProvider = p->context_->map_provider(); + const auto& mapProviderInfo = GetMapProviderInfo(mapProvider); auto& styles = mapProviderInfo.mapStyles_; p->currentStyle_ = &styles[p->currentStyleIndex_]; logger_->debug("Updating style: {}", styles[p->currentStyleIndex_].name_); - util::maplibre::SetMapStyleUrl( - p->map_, p->mapProvider_, styles[p->currentStyleIndex_].url_); + util::maplibre::SetMapStyleUrl(p->context_, + styles[p->currentStyleIndex_].url_); if (++p->currentStyleIndex_ == styles.size()) { @@ -1135,10 +1154,7 @@ void MapWidget::initializeGL() p->map_.reset( new QMapLibre::Map(nullptr, p->settings_, size(), pixelRatio())); p->context_->set_map(p->map_); - connect(p->map_.get(), - &QMapLibre::Map::needsRendering, - p.get(), - &MapWidgetImpl::Update); + p->ConnectMapSignals(); // Set default location to radar site std::shared_ptr radarSite = diff --git a/scwx-qt/source/scwx/qt/util/maplibre.cpp b/scwx-qt/source/scwx/qt/util/maplibre.cpp index 0adff1ed..3414af41 100644 --- a/scwx-qt/source/scwx/qt/util/maplibre.cpp +++ b/scwx-qt/source/scwx/qt/util/maplibre.cpp @@ -88,10 +88,11 @@ glm::vec2 LatLongToScreenCoordinate(const QMapLibre::Coordinate& coordinate) return screen; } -void SetMapStyleUrl(const std::shared_ptr& map, - map::MapProvider mapProvider, - const std::string& url) +void SetMapStyleUrl(const std::shared_ptr& mapContext, + const std::string& url) { + const auto mapProvider = mapContext->map_provider(); + QString qUrl = QString::fromStdString(url); if (mapProvider == map::MapProvider::MapTiler) @@ -100,7 +101,11 @@ void SetMapStyleUrl(const std::shared_ptr& map, qUrl.append(map::GetMapProviderApiKey(mapProvider)); } - map->setStyleUrl(qUrl); + auto map = mapContext->map().lock(); + if (map != nullptr) + { + map->setStyleUrl(qUrl); + } } } // namespace maplibre diff --git a/scwx-qt/source/scwx/qt/util/maplibre.hpp b/scwx-qt/source/scwx/qt/util/maplibre.hpp index 619ba2ca..7c2eb58b 100644 --- a/scwx-qt/source/scwx/qt/util/maplibre.hpp +++ b/scwx-qt/source/scwx/qt/util/maplibre.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -34,9 +34,8 @@ bool IsPointInPolygon(const std::vector& vertices, glm::vec2 LatLongToScreenCoordinate(const QMapLibre::Coordinate& coordinate); -void SetMapStyleUrl(const std::shared_ptr& map, - map::MapProvider mapProvider, - const std::string& url); +void SetMapStyleUrl(const std::shared_ptr& mapContext, + const std::string& url); } // namespace maplibre } // namespace util From b09abc0ac1131e5502585ffd3ea1f8719355603c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 2 Mar 2024 23:41:02 -0600 Subject: [PATCH 15/33] Add color table margins to map context --- scwx-qt/source/scwx/qt/map/color_table_layer.cpp | 8 ++++++++ scwx-qt/source/scwx/qt/map/map_context.cpp | 12 ++++++++++++ scwx-qt/source/scwx/qt/map/map_context.hpp | 3 +++ 3 files changed, 23 insertions(+) diff --git a/scwx-qt/source/scwx/qt/map/color_table_layer.cpp b/scwx-qt/source/scwx/qt/map/color_table_layer.cpp index 20d9c9dc..bdafce3f 100644 --- a/scwx-qt/source/scwx/qt/map/color_table_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/color_table_layer.cpp @@ -181,6 +181,12 @@ void ColorTableLayer::Render( gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[0]); gl.glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); gl.glDrawArrays(GL_TRIANGLES, 0, 6); + + context()->set_color_table_margins(QMargins {0, 0, 0, 10}); + } + else + { + context()->set_color_table_margins(QMargins {}); } SCWX_GL_CHECK_ERROR(); @@ -200,6 +206,8 @@ void ColorTableLayer::Deinitialize() p->vao_ = GL_INVALID_INDEX; p->vbo_ = {GL_INVALID_INDEX}; p->texture_ = GL_INVALID_INDEX; + + context()->set_color_table_margins(QMargins {}); } } // namespace map diff --git a/scwx-qt/source/scwx/qt/map/map_context.cpp b/scwx-qt/source/scwx/qt/map/map_context.cpp index 14a9c559..d7e4f224 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.cpp +++ b/scwx-qt/source/scwx/qt/map/map_context.cpp @@ -32,6 +32,8 @@ public: MapProvider mapProvider_ {MapProvider::Unknown}; std::string mapCopyrights_ {}; + QMargins colorTableMargins_ {}; + std::shared_ptr overlayProductView_ {nullptr}; std::shared_ptr radarProductView_; }; @@ -66,6 +68,11 @@ MapSettings& MapContext::settings() return p->settings_; } +QMargins MapContext::color_table_margins() const +{ + return p->colorTableMargins_; +} + float MapContext::pixel_ratio() const { return p->pixelRatio_; @@ -117,6 +124,11 @@ void MapContext::set_map_provider(MapProvider provider) p->mapProvider_ = provider; } +void MapContext::set_color_table_margins(const QMargins& margins) +{ + p->colorTableMargins_ = margins; +} + void MapContext::set_overlay_product_view( const std::shared_ptr& overlayProductView) { diff --git a/scwx-qt/source/scwx/qt/map/map_context.hpp b/scwx-qt/source/scwx/qt/map/map_context.hpp index 367c1006..55136886 100644 --- a/scwx-qt/source/scwx/qt/map/map_context.hpp +++ b/scwx-qt/source/scwx/qt/map/map_context.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace scwx { @@ -40,6 +41,7 @@ public: std::string map_copyrights() const; MapProvider map_provider() const; MapSettings& settings(); + QMargins color_table_margins() const; float pixel_ratio() const; std::shared_ptr overlay_product_view() const; std::shared_ptr radar_product_view() const; @@ -51,6 +53,7 @@ public: void set_map(const std::shared_ptr& map); void set_map_copyrights(const std::string& copyrights); void set_map_provider(MapProvider provider); + void set_color_table_margins(const QMargins& margins); void set_overlay_product_view( const std::shared_ptr& overlayProductView); void set_pixel_ratio(float pixelRatio); From 2a8a16e79fd1c62c0d172e8ca9048f5457a00650 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 2 Mar 2024 23:41:37 -0600 Subject: [PATCH 16/33] Add map attribution to display --- scwx-qt/source/scwx/qt/map/overlay_layer.cpp | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp index afd88b7f..540aa8d1 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -355,6 +356,31 @@ void OverlayLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) ImGui::End(); } + auto mapCopyrights = context()->map_copyrights(); + if (mapCopyrights.length() > 0) + { + auto attributionFont = manager::FontManager::Instance().GetImGuiFont( + types::FontCategory::Attribution); + + ImGui::SetNextWindowPos( + ImVec2 {static_cast(params.width), + static_cast(params.height) - + context()->color_table_margins().bottom()}, + ImGuiCond_Always, + ImVec2 {1.0f, 1.0f}); + ImGui::SetNextWindowBgAlpha(0.5f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2 {3.0f, 2.0f}); + ImGui::PushFont(attributionFont->font()); + ImGui::Begin("Attribution", + nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_AlwaysAutoResize); + ImGui::TextUnformatted(mapCopyrights.c_str()); + ImGui::End(); + ImGui::PopFont(); + ImGui::PopStyleVar(); + } + p->lastWidth_ = params.width; p->lastHeight_ = params.height; p->lastBearing_ = params.bearing; From 1ad188546af127b42191cad64f161ce87a032d5c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 4 Mar 2024 00:51:14 -0600 Subject: [PATCH 17/33] Support SVG image loading --- scwx-qt/scwx-qt.cmake | 3 + scwx-qt/source/scwx/qt/util/texture_atlas.cpp | 101 ++++++++++++++---- 2 files changed, 84 insertions(+), 20 deletions(-) diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index d0121e40..65dd81b3 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -28,6 +28,7 @@ find_package(QT NAMES Qt6 OpenGL OpenGLWidgets Positioning + Svg Widgets REQUIRED) find_package(Qt${QT_VERSION_MAJOR} @@ -38,6 +39,7 @@ find_package(Qt${QT_VERSION_MAJOR} OpenGL OpenGLWidgets Positioning + Svg Widgets REQUIRED) @@ -552,6 +554,7 @@ target_link_libraries(scwx-qt PUBLIC Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::OpenGLWidgets Qt${QT_VERSION_MAJOR}::Multimedia Qt${QT_VERSION_MAJOR}::Positioning + Qt${QT_VERSION_MAJOR}::Svg Boost::json Boost::timer QMapLibre::Core diff --git a/scwx-qt/source/scwx/qt/util/texture_atlas.cpp b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp index fbb4f187..554cecbe 100644 --- a/scwx-qt/source/scwx/qt/util/texture_atlas.cpp +++ b/scwx-qt/source/scwx/qt/util/texture_atlas.cpp @@ -20,6 +20,9 @@ #include #include #include +#include +#include +#include #include #if defined(_MSC_VER) @@ -49,6 +52,11 @@ public: static std::shared_ptr LoadImage(const std::string& imagePath); + static std::shared_ptr + ReadPngFile(const QString& imagePath); + static std::shared_ptr + ReadSvgFile(const QString& imagePath); + std::vector> registeredTextures_ {}; std::shared_mutex registeredTextureMutex_ {}; @@ -376,34 +384,23 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath) { logger_->debug("Loading image: {}", imagePath); - std::shared_ptr image = - std::make_shared(); + std::shared_ptr image = nullptr; - QUrl url = QUrl::fromUserInput(QString::fromStdString(imagePath)); + QString qImagePath = QString::fromStdString(imagePath); + + QUrl url = QUrl::fromUserInput(qImagePath); if (url.isLocalFile()) { - QFile imageFile(imagePath.c_str()); + QString suffix = QFileInfo(qImagePath).suffix().toLower(); - imageFile.open(QIODevice::ReadOnly); - - if (!imageFile.isOpen()) + if (suffix == "svg") { - logger_->error("Could not open image: {}", imagePath); - return nullptr; + image = ReadSvgFile(qImagePath); } - - boost::iostreams::stream dataStream(imageFile); - - try + else { - boost::gil::read_and_convert_image( - dataStream, *image, boost::gil::png_tag()); - } - catch (const std::exception& ex) - { - logger_->error("Error reading image: {}", ex.what()); - return nullptr; + image = ReadPngFile(qImagePath); } } else @@ -442,6 +439,7 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath) width * desiredChannels); // Copy the view to the destination image + image = std::make_shared(); *image = boost::gil::rgba8_image_t(stbView); auto& view = boost::gil::view(*image); @@ -477,6 +475,69 @@ TextureAtlas::Impl::LoadImage(const std::string& imagePath) return image; } +std::shared_ptr +TextureAtlas::Impl::ReadPngFile(const QString& imagePath) +{ + QFile imageFile(imagePath); + + imageFile.open(QIODevice::ReadOnly); + + if (!imageFile.isOpen()) + { + logger_->error("Could not open image: {}", imagePath.toStdString()); + return nullptr; + } + + boost::iostreams::stream dataStream(imageFile); + std::shared_ptr image = + std::make_shared(); + + try + { + boost::gil::read_and_convert_image( + dataStream, *image, boost::gil::png_tag()); + } + catch (const std::exception& ex) + { + logger_->error("Error reading image: {}", ex.what()); + return nullptr; + } + + return image; +} + +std::shared_ptr +TextureAtlas::Impl::ReadSvgFile(const QString& imagePath) +{ + QSvgRenderer renderer {imagePath}; + QPixmap pixmap {renderer.defaultSize()}; + pixmap.fill(Qt::GlobalColor::transparent); + + QPainter painter {&pixmap}; + renderer.render(&painter, pixmap.rect()); + + QImage qImage = pixmap.toImage(); + + std::shared_ptr image = nullptr; + + if (qImage.width() > 0 && qImage.height() > 0) + { + // Convert to ARGB32 format if not already (equivalent to bgra8_pixel_t) + qImage.convertTo(QImage::Format_ARGB32); + + // Create a view pointing to the underlying QImage pixel data + auto view = boost::gil::interleaved_view( + qImage.width(), + qImage.height(), + reinterpret_cast(qImage.constBits()), + qImage.width() * 4); + + image = std::make_shared(view); + } + + return image; +} + TextureAtlas& TextureAtlas::Instance() { static TextureAtlas instance_ {}; From 896f111b38de5192d738d38f3c141629e99bc9c6 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 4 Mar 2024 00:52:14 -0600 Subject: [PATCH 18/33] Only set target properties on update_translations if it exists --- scwx-qt/scwx-qt.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 65dd81b3..f444dd77 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -472,7 +472,10 @@ set_target_properties(release_translations PROPERTIES FOLDER qt) set_target_properties(scwx-qt_lrelease PROPERTIES FOLDER qt) set_target_properties(scwx-qt_lupdate PROPERTIES FOLDER qt) set_target_properties(scwx-qt_other_files PROPERTIES FOLDER qt) -set_target_properties(update_translations PROPERTIES FOLDER qt) + +if (TARGET update_translations) + set_target_properties(update_translations PROPERTIES FOLDER qt) +endif() set_target_properties(scwx-qt_generate_counties_db PROPERTIES FOLDER generate) set_target_properties(scwx-qt_generate_versions PROPERTIES FOLDER generate) From 50e0036e0b240515833c2d16e1097851a24fb411 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 4 Mar 2024 00:52:46 -0600 Subject: [PATCH 19/33] Add Mapbox and MapTiler logos --- scwx-qt/res/textures/images/mapbox-logo.svg | 1 + scwx-qt/res/textures/images/maptiler-logo.svg | 13 +++++++++++++ scwx-qt/scwx-qt.qrc | 2 ++ scwx-qt/source/scwx/qt/types/texture_types.cpp | 6 +++++- scwx-qt/source/scwx/qt/types/texture_types.hpp | 6 ++++-- 5 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 scwx-qt/res/textures/images/mapbox-logo.svg create mode 100644 scwx-qt/res/textures/images/maptiler-logo.svg diff --git a/scwx-qt/res/textures/images/mapbox-logo.svg b/scwx-qt/res/textures/images/mapbox-logo.svg new file mode 100644 index 00000000..60fe0169 --- /dev/null +++ b/scwx-qt/res/textures/images/mapbox-logo.svg @@ -0,0 +1 @@ + diff --git a/scwx-qt/res/textures/images/maptiler-logo.svg b/scwx-qt/res/textures/images/maptiler-logo.svg new file mode 100644 index 00000000..55e978a4 --- /dev/null +++ b/scwx-qt/res/textures/images/maptiler-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/scwx-qt/scwx-qt.qrc b/scwx-qt/scwx-qt.qrc index 4bc8a324..d917c977 100644 --- a/scwx-qt/scwx-qt.qrc +++ b/scwx-qt/scwx-qt.qrc @@ -70,5 +70,7 @@ res/textures/lines/default-1x7.png res/textures/lines/test-pattern.png res/textures/images/crosshairs-24.png + res/textures/images/mapbox-logo.svg + res/textures/images/maptiler-logo.svg diff --git a/scwx-qt/source/scwx/qt/types/texture_types.cpp b/scwx-qt/source/scwx/qt/types/texture_types.cpp index 569e0f41..f38038a7 100644 --- a/scwx-qt/source/scwx/qt/types/texture_types.cpp +++ b/scwx-qt/source/scwx/qt/types/texture_types.cpp @@ -21,7 +21,11 @@ static const std::unordered_map imageTextureInfo_ { {ImageTexture::Compass24, {"images/compass-24", ":/res/icons/flaticon/compass-24.png"}}, {ImageTexture::Crosshairs24, - {"images/crosshairs-24", ":/res/textures/images/crosshairs-24.png"}}}; + {"images/crosshairs-24", ":/res/textures/images/crosshairs-24.png"}}, + {ImageTexture::MapboxLogo, + {"images/mapbox-logo", ":/res/textures/images/mapbox-logo.svg"}}, + {ImageTexture::MapTilerLogo, + {"images/maptiler-logo", ":/res/textures/images/maptiler-logo.svg"}}}; static const std::unordered_map lineTextureInfo_ { {LineTexture::Default1x7, diff --git a/scwx-qt/source/scwx/qt/types/texture_types.hpp b/scwx-qt/source/scwx/qt/types/texture_types.hpp index ea94162a..be3839ec 100644 --- a/scwx-qt/source/scwx/qt/types/texture_types.hpp +++ b/scwx-qt/source/scwx/qt/types/texture_types.hpp @@ -15,11 +15,13 @@ enum class ImageTexture { CardinalPoint24, Compass24, - Crosshairs24 + Crosshairs24, + MapboxLogo, + MapTilerLogo }; typedef scwx::util::Iterator + ImageTexture::MapTilerLogo> ImageTextureIterator; enum class LineTexture From f6ac027725435d846e1bde3d8d0506b8161d29da Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 5 Mar 2024 22:55:42 -0600 Subject: [PATCH 20/33] Allow icons to have a variable anchor --- scwx-qt/source/scwx/qt/gl/draw/icons.cpp | 60 +++++++++++---------- scwx-qt/source/scwx/qt/gl/draw/icons.hpp | 13 +++-- scwx-qt/source/scwx/qt/types/icon_types.cpp | 25 ++++++++- scwx-qt/source/scwx/qt/types/icon_types.hpp | 5 ++ 4 files changed, 67 insertions(+), 36 deletions(-) diff --git a/scwx-qt/source/scwx/qt/gl/draw/icons.cpp b/scwx-qt/source/scwx/qt/gl/draw/icons.cpp index 86e7e542..d2c3d709 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/icons.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/icons.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -80,9 +79,10 @@ public: std::mutex iconMutex_; - boost::unordered_flat_map + boost::unordered_flat_map> currentIconSheets_ {}; - boost::unordered_flat_map newIconSheets_ {}; + boost::unordered_flat_map> + newIconSheets_ {}; std::vector> currentIconList_ {}; std::vector> newIconList_ {}; @@ -243,17 +243,19 @@ void Icons::StartIconSheets() p->newIconSheets_.clear(); } -void Icons::AddIconSheet(const std::string& name, - std::size_t iconWidth, - std::size_t iconHeight, - std::int32_t hotX, - std::int32_t hotY) +std::shared_ptr Icons::AddIconSheet(const std::string& name, + std::size_t iconWidth, + std::size_t iconHeight, + std::int32_t hotX, + std::int32_t hotY) { // Populate icon sheet map - p->newIconSheets_.emplace(std::piecewise_construct, - std::tuple {name}, - std::forward_as_tuple(types::IconInfo { - name, iconWidth, iconHeight, hotX, hotY})); + return p->newIconSheets_ + .emplace(std::piecewise_construct, + std::tuple {name}, + std::forward_as_tuple(std::make_shared( + name, iconWidth, iconHeight, hotX, hotY))) + .first->second; } void Icons::FinishIconSheets() @@ -261,7 +263,7 @@ void Icons::FinishIconSheets() // Update icon sheets for (auto& iconSheet : p->newIconSheets_) { - iconSheet.second.UpdateTextureInfo(); + iconSheet.second->UpdateTextureInfo(); } std::unique_lock lock {p->iconMutex_}; @@ -375,7 +377,7 @@ void Icons::Impl::UpdateBuffers() auto& icon = it->second; // Validate icon - if (di->iconIndex_ >= icon.numIcons_) + if (di->iconIndex_ >= icon->numIcons_) { // No icon found logger_->warn("Invalid icon index: {}", di->iconIndex_); @@ -390,12 +392,12 @@ void Icons::Impl::UpdateBuffers() const float y = static_cast(di->y_); // Icon size - const float iw = static_cast(icon.iconWidth_); - const float ih = static_cast(icon.iconHeight_); + const float iw = static_cast(icon->iconWidth_); + const float ih = static_cast(icon->iconHeight_); // Hot X/Y (zero-based icon center) - const float hx = static_cast(icon.hotX_); - const float hy = static_cast(icon.hotY_); + const float hx = static_cast(icon->hotX_); + const float hy = static_cast(icon->hotY_); // Final X/Y offsets in pixels const float lx = std::roundf(-hx); @@ -477,7 +479,7 @@ void Icons::Impl::UpdateTextureBuffer() auto& icon = it->second; // Validate icon - if (di->iconIndex_ >= icon.numIcons_) + if (di->iconIndex_ >= icon->numIcons_) { // No icon found logger_->error("Invalid icon index: {}", di->iconIndex_); @@ -503,17 +505,17 @@ void Icons::Impl::UpdateTextureBuffer() } // Texture coordinates - const std::size_t iconRow = (di->iconIndex_) / icon.columns_; - const std::size_t iconColumn = (di->iconIndex_) % icon.columns_; + const std::size_t iconRow = (di->iconIndex_) / icon->columns_; + const std::size_t iconColumn = (di->iconIndex_) % icon->columns_; - const float iconX = iconColumn * icon.scaledWidth_; - const float iconY = iconRow * icon.scaledHeight_; + const float iconX = iconColumn * icon->scaledWidth_; + const float iconY = iconRow * icon->scaledHeight_; - const float ls = icon.texture_.sLeft_ + iconX; - const float rs = ls + icon.scaledWidth_; - const float tt = icon.texture_.tTop_ + iconY; - const float bt = tt + icon.scaledHeight_; - const float r = static_cast(icon.texture_.layerId_); + const float ls = icon->texture_.sLeft_ + iconX; + const float rs = ls + icon->scaledWidth_; + const float tt = icon->texture_.tTop_ + iconY; + const float bt = tt + icon->scaledHeight_; + const float r = static_cast(icon->texture_.layerId_); // clang-format off textureBuffer_.insert( @@ -541,7 +543,7 @@ void Icons::Impl::Update(bool textureAtlasChanged) // Update texture coordinates for (auto& iconSheet : currentIconSheets_) { - iconSheet.second.UpdateTextureInfo(); + iconSheet.second->UpdateTextureInfo(); } // Update OpenGL texture buffer data diff --git a/scwx-qt/source/scwx/qt/gl/draw/icons.hpp b/scwx-qt/source/scwx/qt/gl/draw/icons.hpp index d7207a11..f9e4c91c 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/icons.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/icons.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -69,12 +70,14 @@ public: * Default is -1 to center the icon. * @param [in] hotY The zero-based center of the each icon in the icon sheet. * Default is -1 to center the icon. + * + * @return Icon info */ - void AddIconSheet(const std::string& name, - std::size_t iconWidth = 0, - std::size_t iconHeight = 0, - std::int32_t hotX = -1, - std::int32_t hotY = -1); + std::shared_ptr AddIconSheet(const std::string& name, + std::size_t iconWidth = 0, + std::size_t iconHeight = 0, + std::int32_t hotX = -1, + std::int32_t hotY = -1); /** * Resets and prepares the draw item for adding a new set of icon sheets. diff --git a/scwx-qt/source/scwx/qt/types/icon_types.cpp b/scwx-qt/source/scwx/qt/types/icon_types.cpp index 8323ef83..87bdb631 100644 --- a/scwx-qt/source/scwx/qt/types/icon_types.cpp +++ b/scwx-qt/source/scwx/qt/types/icon_types.cpp @@ -7,6 +7,11 @@ namespace qt namespace types { +void IconInfo::SetAnchor(float anchorX, float anchorY) +{ + anchor_ = {anchorX, anchorY}; +} + void IconInfo::UpdateTextureInfo() { texture_ = util::TextureAtlas::Instance().GetTextureAttributes(iconSheet_); @@ -27,8 +32,24 @@ void IconInfo::UpdateTextureInfo() if (hotX_ == -1 || hotY_ == -1) { - hotX_ = static_cast(iconWidth_ / 2); - hotY_ = static_cast(iconHeight_ / 2); + if (anchor_.has_value()) + { + hotX_ = + std::clamp(static_cast(std::lround( + iconWidth_ * anchor_.value().first)), + 0, + static_cast(iconWidth_)); + hotY_ = + std::clamp(static_cast(std::lround( + iconHeight_ * anchor_.value().second)), + 0, + static_cast(iconHeight_)); + } + else + { + hotX_ = static_cast(iconWidth_ / 2); + hotY_ = static_cast(iconHeight_ / 2); + } } numIcons_ = columns_ * rows_; diff --git a/scwx-qt/source/scwx/qt/types/icon_types.hpp b/scwx-qt/source/scwx/qt/types/icon_types.hpp index c6ae7abe..4535012c 100644 --- a/scwx-qt/source/scwx/qt/types/icon_types.hpp +++ b/scwx-qt/source/scwx/qt/types/icon_types.hpp @@ -2,7 +2,9 @@ #include +#include #include +#include namespace scwx { @@ -26,6 +28,7 @@ struct IconInfo { } + void SetAnchor(float anchorX, float anchorY); void UpdateTextureInfo(); std::string iconSheet_; @@ -39,6 +42,8 @@ struct IconInfo std::size_t numIcons_ {}; float scaledWidth_ {}; float scaledHeight_ {}; + + std::optional> anchor_ {}; }; } // namespace types From 074a39d2249f3142441d2d5f637202665bebb116 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 5 Mar 2024 22:56:27 -0600 Subject: [PATCH 21/33] Add map logo to map --- scwx-qt/source/scwx/qt/map/overlay_layer.cpp | 62 ++++++++++++++++---- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp index 540aa8d1..52e1418c 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp @@ -67,13 +67,23 @@ public: types::GetTextureName(types::ImageTexture::CardinalPoint24)}; const std::string& compassIconName_ { types::GetTextureName(types::ImageTexture::Compass24)}; + + const std::string& mapboxLogoImageName_ { + types::GetTextureName(types::ImageTexture::MapboxLogo)}; + const std::string& mapTilerLogoImageName_ { + types::GetTextureName(types::ImageTexture::MapTilerLogo)}; + std::shared_ptr compassIcon_ {}; bool compassIconDirty_ {false}; double lastBearing_ {0.0}; - double lastWidth_ {0.0}; - double lastHeight_ {0.0}; - float lastFontSize_ {0.0f}; + std::shared_ptr mapLogoIcon_ {}; + + bool firstRender_ {true}; + double lastWidth_ {0.0}; + double lastHeight_ {0.0}; + float lastFontSize_ {0.0f}; + QMargins lastColorTableMargins_ {}; std::string sweepTimeString_ {}; bool sweepTimeNeedsUpdate_ {true}; @@ -131,6 +141,8 @@ void OverlayLayer::Initialize() p->icons_->StartIconSheets(); p->icons_->AddIconSheet(p->cardinalPointIconName_); p->icons_->AddIconSheet(p->compassIconName_); + p->icons_->AddIconSheet(p->mapboxLogoImageName_)->SetAnchor(0.0f, 1.0f); + p->icons_->AddIconSheet(p->mapTilerLogoImageName_)->SetAnchor(0.0f, 1.0f); p->icons_->FinishIconSheets(); p->icons_->StartIcons(); @@ -180,6 +192,19 @@ void OverlayLayer::Initialize() break; } }); + + p->mapLogoIcon_ = p->icons_->AddIcon(); + if (context()->map_provider() == MapProvider::Mapbox) + { + gl::draw::Icons::SetIconTexture( + p->mapLogoIcon_, p->mapboxLogoImageName_, 0); + } + else if (context()->map_provider() == MapProvider::MapTiler) + { + gl::draw::Icons::SetIconTexture( + p->mapLogoIcon_, p->mapTilerLogoImageName_, 0); + } + p->icons_->FinishIcons(); connect(p->positionManager_.get(), @@ -356,18 +381,27 @@ void OverlayLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) ImGui::End(); } + QMargins colorTableMargins = context()->color_table_margins(); + if (colorTableMargins != p->lastColorTableMargins_ || p->firstRender_) + { + // Draw map logo with a 10x10 indent from the bottom left + gl::draw::Icons::SetIconLocation(p->mapLogoIcon_, + 10 + colorTableMargins.left(), + 10 + colorTableMargins.bottom()); + p->icons_->FinishIcons(); + } + auto mapCopyrights = context()->map_copyrights(); if (mapCopyrights.length() > 0) { auto attributionFont = manager::FontManager::Instance().GetImGuiFont( types::FontCategory::Attribution); - ImGui::SetNextWindowPos( - ImVec2 {static_cast(params.width), - static_cast(params.height) - - context()->color_table_margins().bottom()}, - ImGuiCond_Always, - ImVec2 {1.0f, 1.0f}); + ImGui::SetNextWindowPos(ImVec2 {static_cast(params.width), + static_cast(params.height) - + colorTableMargins.bottom()}, + ImGuiCond_Always, + ImVec2 {1.0f, 1.0f}); ImGui::SetNextWindowBgAlpha(0.5f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2 {3.0f, 2.0f}); ImGui::PushFont(attributionFont->font()); @@ -381,10 +415,12 @@ void OverlayLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) ImGui::PopStyleVar(); } - p->lastWidth_ = params.width; - p->lastHeight_ = params.height; - p->lastBearing_ = params.bearing; - p->lastFontSize_ = ImGui::GetFontSize(); + p->firstRender_ = false; + p->lastWidth_ = params.width; + p->lastHeight_ = params.height; + p->lastBearing_ = params.bearing; + p->lastFontSize_ = ImGui::GetFontSize(); + p->lastColorTableMargins_ = colorTableMargins; SCWX_GL_CHECK_ERROR(); } From 6ac2ea00fcb7e0f151115c3f2c8ef6606a86ec0d Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 5 Mar 2024 22:58:25 -0600 Subject: [PATCH 22/33] Fix crash in maplibre-native when changing map styles --- .gitmodules | 2 +- external/maplibre-native | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index adb166fa..0e93c30e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -36,4 +36,4 @@ url = https://github.com/maplibre/maplibre-native-qt.git [submodule "external/maplibre-native"] path = external/maplibre-native - url = https://github.com/maplibre/maplibre-native.git + url = https://github.com/dpaulat/maplibre-gl-native.git diff --git a/external/maplibre-native b/external/maplibre-native index 4fff8a5d..6932d9b4 160000 --- a/external/maplibre-native +++ b/external/maplibre-native @@ -1 +1 @@ -Subproject commit 4fff8a5d33852c7bc4c5d8c989092eb42769a71d +Subproject commit 6932d9b49cf01ac75b79aff9f9a9f0f9ce97a9ae From 8af480198be5a5394f149e727520aa5a55e2f442 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 5 Mar 2024 23:35:30 -0600 Subject: [PATCH 23/33] Add additional Mapbox map styles from the Mapbox gallery --- scwx-qt/source/scwx/qt/map/map_provider.cpp | 46 +++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/scwx-qt/source/scwx/qt/map/map_provider.cpp b/scwx-qt/source/scwx/qt/map/map_provider.cpp index c0d7f470..7d916072 100644 --- a/scwx-qt/source/scwx/qt/map/map_provider.cpp +++ b/scwx-qt/source/scwx/qt/map/map_provider.cpp @@ -32,6 +32,10 @@ static const std::unordered_map mapProviderInfo_ { {.name_ {"Streets"}, .url_ {"mapbox://styles/mapbox/streets-v11"}, .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"American Memory"}, + .url_ { + "mapbox://styles/mapbox-map-design/cl4orrp5e000p14ldwenm7xsf"}, + .drawBelow_ {mapboxDrawBelow_}}, {.name_ {"Basic"}, .url_ { "mapbox://styles/mapbox-map-design/cl4whef7m000714pc44f3qaxs"}, @@ -40,25 +44,67 @@ static const std::unordered_map mapProviderInfo_ { .url_ { "mapbox://styles/mapbox-map-design/cl4whev1w002w16s9mgoliotw"}, .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Blueprint"}, + .url_ { + "mapbox://styles/mapbox-map-design/cks97e1e37nsd17nzg7p0308g"}, + .drawBelow_ {mapboxDrawBelow_}}, {.name_ {"Bubble"}, .url_ { "mapbox://styles/mapbox-map-design/cl4wxue5j000c14r17uqrjpqb"}, .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Cali Terrain"}, + .url_ {"mapbox://styles/mapbox/cjerxnqt3cgvp2rmyuxbeqme7"}, + .drawBelow_ {"major roads casing"}}, {.name_ {"Dark"}, .url_ {"mapbox://styles/mapbox/dark-v10"}, .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Decimal"}, + .url_ { + "mapbox://styles/mapbox-map-design/ck4014y110wt61ctt07egsel6"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Frank"}, + .url_ { + "mapbox://styles/mapbox-map-design/ckshxkppe0gge18nz20i0nrwq"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Ice Cream"}, + .url_ {"mapbox://styles/mapbox/cj7t3i5yj0unt2rmt3y4b5e32"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Le Shine"}, + .url_ {"mapbox://styles/mapbox/cjcunv5ae262f2sm9tfwg8i0w"}, + .drawBelow_ {mapboxDrawBelow_}}, {.name_ {"Light"}, .url_ {"mapbox://styles/mapbox/light-v10"}, .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Mineral"}, + .url_ {"mapbox://styles/mapbox/cjtep62gq54l21frr1whf27ak"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Minimo"}, + .url_ { + "mapbox://styles/mapbox-map-design/cksjc2nsq1bg117pnekb655h1"}, + .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Moonlight"}, + .url_ {"mapbox://styles/mapbox/cj3kbeqzo00022smj7akz3o1e"}, + .drawBelow_ {mapboxDrawBelow_}}, {.name_ {"Navigation Guidance Day"}, .url_ {"mapbox://styles/mapbox/navigation-guidance-day-v4"}, .drawBelow_ {mapboxDrawBelow_}}, {.name_ {"Navigation Guidance Night"}, .url_ {"mapbox://styles/mapbox/navigation-guidance-night-v4"}, .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Neon glow"}, + .url_ { + "mapbox://styles/mapbox-map-design/cl4gxqwi5001415l381n7qwak"}, + .drawBelow_ {"settlement-minor-label"}}, + {.name_ {"North Star"}, + .url_ {"mapbox://styles/mapbox/cj44mfrt20f082snokim4ungi"}, + .drawBelow_ {mapboxDrawBelow_}}, {.name_ {"Outdoors"}, .url_ {"mapbox://styles/mapbox/outdoors-v11"}, .drawBelow_ {mapboxDrawBelow_}}, + {.name_ {"Pencil"}, + .url_ { + "mapbox://styles/mapbox-map-design/cks9iema71es417mlrft4go2k"}, + .drawBelow_ {mapboxDrawBelow_}}, {.name_ {"Satellite"}, .url_ {"mapbox://styles/mapbox/satellite-v9"}, .drawBelow_ {"com.mapbox.annotations.points"}}, From 54e85e981b6afe62c909fe80c681fb2fda351d5a Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 5 Mar 2024 23:48:15 -0600 Subject: [PATCH 24/33] Remove "Improve this map" where HTML links cannot be shown --- scwx-qt/source/scwx/qt/map/map_widget.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp index 90139d19..e64ef32b 100644 --- a/scwx-qt/source/scwx/qt/map/map_widget.cpp +++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp @@ -30,6 +30,8 @@ #include #include +#include +#include #include #include #include @@ -263,8 +265,14 @@ void MapWidgetImpl::ConnectMapSignals() { QTextDocument document {}; document.setHtml(copyrightsHtml); - context_->set_map_copyrights( - document.toPlainText().toStdString()); + + // HTML cannot currently be included in ImGui windows. Where links + // can't be included, remove "Improve this map". + std::string copyrights {document.toPlainText().toStdString()}; + boost::erase_all(copyrights, "Improve this map"); + boost::trim_right(copyrights); + + context_->set_map_copyrights(copyrights); }); } From 17373fd57064fa01831283607823361761f534d1 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 6 Mar 2024 00:27:38 -0600 Subject: [PATCH 25/33] Don't set mbgl-vendor-sqlite target properties if it doesn't exist --- external/maplibre-native-qt.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/external/maplibre-native-qt.cmake b/external/maplibre-native-qt.cmake index aae9d40b..9d44009b 100644 --- a/external/maplibre-native-qt.cmake +++ b/external/maplibre-native-qt.cmake @@ -41,4 +41,7 @@ set_target_properties(mbgl-core PROPERTIES FOLDER mln) set_target_properties(mbgl-vendor-csscolorparser PROPERTIES FOLDER mln) set_target_properties(mbgl-vendor-nunicode PROPERTIES FOLDER mln) set_target_properties(mbgl-vendor-parsedate PROPERTIES FOLDER mln) -set_target_properties(mbgl-vendor-sqlite PROPERTIES FOLDER mln) + +if (TARGET mbgl-vendor-sqlite) + set_target_properties(mbgl-vendor-sqlite PROPERTIES FOLDER mln) +endif() From 98bbb446afa4d0e15b8fdb976b586a53f1f2cf1f Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 6 Mar 2024 00:28:03 -0600 Subject: [PATCH 26/33] Updates to maplibre-native-qt for the latest maplibre-native --- .gitmodules | 2 +- external/maplibre-native-qt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 0e93c30e..52ede30b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -33,7 +33,7 @@ url = https://github.com/catchorg/textflowcpp.git [submodule "external/maplibre-native-qt"] path = external/maplibre-native-qt - url = https://github.com/maplibre/maplibre-native-qt.git + url = https://github.com/dpaulat/maplibre-native-qt.git [submodule "external/maplibre-native"] path = external/maplibre-native url = https://github.com/dpaulat/maplibre-gl-native.git diff --git a/external/maplibre-native-qt b/external/maplibre-native-qt index 38dde09f..fe734916 160000 --- a/external/maplibre-native-qt +++ b/external/maplibre-native-qt @@ -1 +1 @@ -Subproject commit 38dde09fee7a267b1762c87ad1eeeeeebb527e44 +Subproject commit fe734916414ce761e053dafaeecafeb19d51509c From 70d1bdcc5825f4749bbeca1524f37fccd1a35aa8 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 6 Mar 2024 21:34:16 -0600 Subject: [PATCH 27/33] Add tests for Roboto Flex as default attribution font --- test/data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data b/test/data index 0446ff70..08d481f3 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit 0446ff708b387728faf8d2dbb3862a757067c2ee +Subproject commit 08d481f3bf96ebd44825359082cfd1243c09a72c From 8e6860731e22c57885e97682b28d5a3bb0abcd1c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 6 Mar 2024 22:20:17 -0600 Subject: [PATCH 28/33] Update AWS data provider tests to use KILX for live data (KLSX currently down) --- test/source/scwx/provider/aws_level2_data_provider.test.cpp | 4 ++-- test/source/scwx/provider/aws_level3_data_provider.test.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/source/scwx/provider/aws_level2_data_provider.test.cpp b/test/source/scwx/provider/aws_level2_data_provider.test.cpp index 66c3dbef..70a9d1d7 100644 --- a/test/source/scwx/provider/aws_level2_data_provider.test.cpp +++ b/test/source/scwx/provider/aws_level2_data_provider.test.cpp @@ -25,7 +25,7 @@ TEST(AwsLevel2DataProvider, FindKeyFixed) TEST(AwsLevel2DataProvider, FindKeyNow) { - AwsLevel2DataProvider provider("KLSX"); + AwsLevel2DataProvider provider("KILX"); provider.Refresh(); std::string key = provider.FindKey(std::chrono::system_clock::now()); @@ -78,7 +78,7 @@ TEST(AwsLevel2DataProvider, Prune) TEST(AwsLevel2DataProvider, Refresh) { - AwsLevel2DataProvider provider("KLSX"); + AwsLevel2DataProvider provider("KILX"); auto [newObjects, totalObjects] = provider.Refresh(); diff --git a/test/source/scwx/provider/aws_level3_data_provider.test.cpp b/test/source/scwx/provider/aws_level3_data_provider.test.cpp index b076d6bb..31ea50ec 100644 --- a/test/source/scwx/provider/aws_level3_data_provider.test.cpp +++ b/test/source/scwx/provider/aws_level3_data_provider.test.cpp @@ -25,7 +25,7 @@ TEST(AwsLevel3DataProvider, FindKeyFixed) TEST(AwsLevel3DataProvider, FindKeyNow) { - AwsLevel3DataProvider provider("KLSX", "N0B"); + AwsLevel3DataProvider provider("KILX", "N0B"); provider.Refresh(); std::string key = provider.FindKey(std::chrono::system_clock::now()); @@ -46,7 +46,7 @@ TEST(AwsLevel3DataProvider, LoadObjectByKey) TEST(AwsLevel3DataProvider, Refresh) { - AwsLevel3DataProvider provider("KLSX", "N0B"); + AwsLevel3DataProvider provider("KILX", "N0B"); auto [newObjects, totalObjects] = provider.Refresh(); @@ -58,7 +58,7 @@ TEST(AwsLevel3DataProvider, Refresh) TEST(AwsLevel3DataProvider, GetAvailableProducts) { - AwsLevel3DataProvider provider("KLSX", "N0B"); + AwsLevel3DataProvider provider("KILX", "N0B"); provider.RequestAvailableProducts(); auto products = provider.GetAvailableProducts(); From 4c844459a001e5951d78399c32addb024a66cfa3 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 6 Mar 2024 22:22:30 -0600 Subject: [PATCH 29/33] Update CI workflow for QMapLibre, upload test logs --- .github/workflows/ci.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a5237b2..c9b269e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,8 +136,8 @@ jobs: objcopy --strip-debug --strip-unneeded supercell-wx cd .. cd lib/ - objcopy --only-keep-debug libQMapLibreGL.so libQMapLibreGL.so.debug - objcopy --strip-debug --strip-unneeded libQMapLibreGL.so + objcopy --only-keep-debug libQMapLibre.so libQMapLibre.so.debug + objcopy --strip-debug --strip-unneeded libQMapLibre.so - name: Install Supercell Wx shell: pwsh @@ -229,4 +229,11 @@ jobs: env: MAPBOX_API_KEY: ${{ secrets.MAPBOX_API_KEY }} MAPTILER_API_KEY: ${{ secrets.MAPTILER_API_KEY }} - run: ctest -C ${{ matrix.build_type }} --exclude-regex mbgl-test-runner + run: ctest -C ${{ matrix.build_type }} --exclude-regex test_mln.* + + - name: Upload Test Logs + if: ${{ !cancelled() }} + uses: actions/upload-artifact@v4 + with: + name: supercell-wx-test-logs-${{ matrix.name }} + path: ${{ github.workspace }}/build/Testing/ From 7cfb55a4defe8fafb526b8144cf51c001eab2aec Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 6 Mar 2024 23:13:18 -0600 Subject: [PATCH 30/33] Add map logo and attribution toggle to settings --- .../scwx/qt/settings/general_settings.cpp | 18 ++++++++++++++++++ .../scwx/qt/settings/general_settings.hpp | 2 ++ scwx-qt/source/scwx/qt/ui/settings_dialog.cpp | 11 +++++++++++ scwx-qt/source/scwx/qt/ui/settings_dialog.ui | 18 ++++++++++++++++-- test/data | 2 +- 5 files changed, 48 insertions(+), 3 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/general_settings.cpp b/scwx-qt/source/scwx/qt/settings/general_settings.cpp index bcf5f5ad..b2f597a3 100644 --- a/scwx-qt/source/scwx/qt/settings/general_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/general_settings.cpp @@ -46,6 +46,8 @@ public: mapProvider_.SetDefault(defaultMapProviderValue); mapboxApiKey_.SetDefault("?"); maptilerApiKey_.SetDefault("?"); + showMapAttribution_.SetDefault(true); + showMapLogo_.SetDefault(true); theme_.SetDefault(defaultThemeValue); trackLocation_.SetDefault(false); updateNotificationsEnabled_.SetDefault(true); @@ -142,6 +144,8 @@ public: SettingsVariable mapProvider_ {"map_provider"}; SettingsVariable mapboxApiKey_ {"mapbox_api_key"}; SettingsVariable maptilerApiKey_ {"maptiler_api_key"}; + SettingsVariable showMapAttribution_ {"show_map_attribution"}; + SettingsVariable showMapLogo_ {"show_map_logo"}; SettingsVariable theme_ {"theme"}; SettingsVariable trackLocation_ {"track_location"}; SettingsVariable updateNotificationsEnabled_ {"update_notifications"}; @@ -163,6 +167,8 @@ GeneralSettings::GeneralSettings() : &p->mapProvider_, &p->mapboxApiKey_, &p->maptilerApiKey_, + &p->showMapAttribution_, + &p->showMapLogo_, &p->theme_, &p->trackLocation_, &p->updateNotificationsEnabled_}); @@ -240,6 +246,16 @@ SettingsVariable& GeneralSettings::maptiler_api_key() const return p->maptilerApiKey_; } +SettingsVariable& GeneralSettings::show_map_attribution() const +{ + return p->showMapAttribution_; +} + +SettingsVariable& GeneralSettings::show_map_logo() const +{ + return p->showMapLogo_; +} + SettingsVariable& GeneralSettings::theme() const { return p->theme_; @@ -289,6 +305,8 @@ bool operator==(const GeneralSettings& lhs, const GeneralSettings& rhs) lhs.p->mapProvider_ == rhs.p->mapProvider_ && lhs.p->mapboxApiKey_ == rhs.p->mapboxApiKey_ && lhs.p->maptilerApiKey_ == rhs.p->maptilerApiKey_ && + lhs.p->showMapAttribution_ == rhs.p->showMapAttribution_ && + lhs.p->showMapLogo_ == rhs.p->showMapLogo_ && lhs.p->theme_ == rhs.p->theme_ && lhs.p->trackLocation_ == rhs.p->trackLocation_ && lhs.p->updateNotificationsEnabled_ == diff --git a/scwx-qt/source/scwx/qt/settings/general_settings.hpp b/scwx-qt/source/scwx/qt/settings/general_settings.hpp index 90c47e5d..984fa995 100644 --- a/scwx-qt/source/scwx/qt/settings/general_settings.hpp +++ b/scwx-qt/source/scwx/qt/settings/general_settings.hpp @@ -38,6 +38,8 @@ public: SettingsVariable& map_provider() const; SettingsVariable& mapbox_api_key() const; SettingsVariable& maptiler_api_key() const; + SettingsVariable& show_map_attribution() const; + SettingsVariable& show_map_logo() const; SettingsVariable& theme() const; SettingsVariable& track_location() const; SettingsVariable& update_notifications_enabled() const; diff --git a/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp b/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp index 8d8c89ec..b7053c0c 100644 --- a/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp @@ -130,6 +130,8 @@ public: &theme_, &defaultAlertAction_, &antiAliasingEnabled_, + &showMapAttribution_, + &showMapLogo_, &updateNotificationsEnabled_, &debugEnabled_, &alertAudioSoundFile_, @@ -220,6 +222,8 @@ public: settings::SettingsInterface defaultAlertAction_ {}; settings::SettingsInterface theme_ {}; settings::SettingsInterface antiAliasingEnabled_ {}; + settings::SettingsInterface showMapAttribution_ {}; + settings::SettingsInterface showMapLogo_ {}; settings::SettingsInterface updateNotificationsEnabled_ {}; settings::SettingsInterface debugEnabled_ {}; @@ -617,6 +621,13 @@ void SettingsDialogImpl::SetupGeneralTab() generalSettings.anti_aliasing_enabled()); antiAliasingEnabled_.SetEditWidget(self_->ui->antiAliasingEnabledCheckBox); + showMapAttribution_.SetSettingsVariable( + generalSettings.show_map_attribution()); + showMapAttribution_.SetEditWidget(self_->ui->showMapAttributionCheckBox); + + showMapLogo_.SetSettingsVariable(generalSettings.show_map_logo()); + showMapLogo_.SetEditWidget(self_->ui->showMapLogoCheckBox); + updateNotificationsEnabled_.SetSettingsVariable( generalSettings.update_notifications_enabled()); updateNotificationsEnabled_.SetEditWidget( diff --git a/scwx-qt/source/scwx/qt/ui/settings_dialog.ui b/scwx-qt/source/scwx/qt/ui/settings_dialog.ui index faf8437e..35f8fcad 100644 --- a/scwx-qt/source/scwx/qt/ui/settings_dialog.ui +++ b/scwx-qt/source/scwx/qt/ui/settings_dialog.ui @@ -322,6 +322,20 @@ + + + + Show Map Attribution + + + + + + + Show Map Logo + + + @@ -373,8 +387,8 @@ 0 0 - 514 - 382 + 66 + 18 diff --git a/test/data b/test/data index 08d481f3..9cef3730 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit 08d481f3bf96ebd44825359082cfd1243c09a72c +Subproject commit 9cef3730c84d22803ea433fba8111826327dd82f From d905abd3e7656fd5913dfb81e36be477936763bf Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 6 Mar 2024 23:54:27 -0600 Subject: [PATCH 31/33] Map provider test fixes --- scwx-qt/source/scwx/qt/map/map_provider.cpp | 2 +- test/source/scwx/qt/map/map_provider.test.cpp | 28 ++++++++++++++----- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/map_provider.cpp b/scwx-qt/source/scwx/qt/map/map_provider.cpp index 7d916072..1648bdc5 100644 --- a/scwx-qt/source/scwx/qt/map/map_provider.cpp +++ b/scwx-qt/source/scwx/qt/map/map_provider.cpp @@ -51,7 +51,7 @@ static const std::unordered_map mapProviderInfo_ { {.name_ {"Bubble"}, .url_ { "mapbox://styles/mapbox-map-design/cl4wxue5j000c14r17uqrjpqb"}, - .drawBelow_ {mapboxDrawBelow_}}, + .drawBelow_ {"com\\.mapbox\\.annotations\\.points"}}, {.name_ {"Cali Terrain"}, .url_ {"mapbox://styles/mapbox/cjerxnqt3cgvp2rmyuxbeqme7"}, .drawBelow_ {"major roads casing"}}, diff --git a/test/source/scwx/qt/map/map_provider.test.cpp b/test/source/scwx/qt/map/map_provider.test.cpp index 3a6a64a5..0f7aff58 100644 --- a/test/source/scwx/qt/map/map_provider.test.cpp +++ b/test/source/scwx/qt/map/map_provider.test.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -47,15 +49,27 @@ TEST_P(ByMapProviderTest, MapProviderLayers) // Configure QMapLibre QMapLibre::Settings mapSettings {}; - mapSettings.setProviderTemplate(mapProviderInfo.providerTemplate_); - mapSettings.setApiKey(QString::fromStdString(apiKey)); + if (mapProvider == map::MapProvider::Mapbox) + { + mapSettings.setProviderTemplate(mapProviderInfo.providerTemplate_); + mapSettings.setApiKey(QString::fromStdString(apiKey)); + } + else if (mapProvider == map::MapProvider::MapTiler) + { + settings::GeneralSettings::Instance().maptiler_api_key().SetValue(apiKey); + } - QMapLibre::Map map(nullptr, mapSettings, QSize(1, 1)); + std::shared_ptr mapContext = + std::make_shared(); + std::shared_ptr map = + std::make_shared(nullptr, mapSettings, QSize(1, 1)); + mapContext->set_map(map); + mapContext->set_map_provider(mapProvider); application.processEvents(); // Connect style load completion signal QObject::connect( - &map, + map.get(), &QMapLibre::Map::mapChanged, [&](QMapLibre::Map::MapChange mapChange) { @@ -88,7 +102,7 @@ TEST_P(ByMapProviderTest, MapProviderLayers) // Load style timeout = false; - map.setStyleUrl(QString::fromStdString(mapStyle.url_)); + util::maplibre::SetMapStyleUrl(mapContext, mapStyle.url_); timeoutTimer.start(5000ms); application.exec(); timeoutTimer.stop(); @@ -97,12 +111,12 @@ TEST_P(ByMapProviderTest, MapProviderLayers) if (!timeout) { // Print layer names for debug - std::string layerIdsString = map.layerIds().join(", ").toStdString(); + std::string layerIdsString = map->layerIds().join(", ").toStdString(); logger_->debug("{} Layers: [{}]", mapStyle.name_, layerIdsString); // Search layer list bool foundMatch = false; - for (const QString& qlayer : map.layerIds()) + for (const QString& qlayer : map->layerIds()) { const std::string layer = qlayer.toStdString(); From 931b5d8481e1bf80032960297cae5a3a72408972 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 8 Mar 2024 00:45:06 -0600 Subject: [PATCH 32/33] Add visibility to icon draw items --- scwx-qt/gl/geo_texture2d.vert | 4 + scwx-qt/gl/map_color.vert | 4 + scwx-qt/gl/texture2d_array.vert | 26 ++- scwx-qt/gl/threshold.geom | 4 +- scwx-qt/source/scwx/qt/gl/draw/icons.cpp | 221 ++++++++++++++----- scwx-qt/source/scwx/qt/gl/draw/icons.hpp | 30 ++- scwx-qt/source/scwx/qt/map/overlay_layer.cpp | 61 +++-- 7 files changed, 248 insertions(+), 102 deletions(-) diff --git a/scwx-qt/gl/geo_texture2d.vert b/scwx-qt/gl/geo_texture2d.vert index 7977af95..a3adeed6 100644 --- a/scwx-qt/gl/geo_texture2d.vert +++ b/scwx-qt/gl/geo_texture2d.vert @@ -25,6 +25,7 @@ out VertexData vec3 texCoord; vec4 color; ivec2 timeRange; + bool displayed; } vsOut; smooth out vec3 texCoord; @@ -41,6 +42,9 @@ vec2 latLngToScreenCoordinate(in vec2 latLng) void main() { + // Always set displayed to true + vsOut.displayed = true; + // Pass the threshold and time range to the geometry shader vsOut.threshold = aThreshold; vsOut.timeRange = aTimeRange; diff --git a/scwx-qt/gl/map_color.vert b/scwx-qt/gl/map_color.vert index 4319310f..d9c207b4 100644 --- a/scwx-qt/gl/map_color.vert +++ b/scwx-qt/gl/map_color.vert @@ -16,12 +16,16 @@ out VertexData vec3 texCoord; vec4 color; ivec2 timeRange; + bool displayed; } vsOut; smooth out vec4 color; void main() { + // Always set displayed to true + vsOut.displayed = true; + // Pass the threshold and time range to the geometry shader vsOut.threshold = aThreshold; vsOut.timeRange = aTimeRange; diff --git a/scwx-qt/gl/texture2d_array.vert b/scwx-qt/gl/texture2d_array.vert index cd250c55..e42f31d4 100644 --- a/scwx-qt/gl/texture2d_array.vert +++ b/scwx-qt/gl/texture2d_array.vert @@ -7,20 +7,42 @@ layout (location = 1) in vec2 aXYOffset; layout (location = 2) in vec3 aTexCoord; layout (location = 3) in vec4 aModulate; layout (location = 4) in float aAngleDeg; +layout (location = 5) in int aDisplayed; uniform mat4 uMVPMatrix; +out VertexData +{ + int threshold; + vec3 texCoord; + vec4 color; + ivec2 timeRange; + bool displayed; +} vsOut; + smooth out vec3 texCoord; smooth out vec4 color; void main() { + // Always set threshold and time range to zero + vsOut.threshold = 0; + vsOut.timeRange = ivec2(0, 0); + + // Pass displayed to the geometry shader + vsOut.displayed = (aDisplayed != 0); + + // Pass the texture coordinate and color modulate to the geometry and + // fragment shaders + vsOut.texCoord = aTexCoord; + vsOut.color = aModulate; + texCoord = aTexCoord; + color = aModulate; + // Rotate clockwise float angle = aAngleDeg * DEG2RAD; mat2 rotate = mat2(cos(angle), -sin(angle), sin(angle), cos(angle)); gl_Position = uMVPMatrix * vec4(aVertex + rotate * aXYOffset, 0.0f, 1.0f); - texCoord = aTexCoord; - color = aModulate; } diff --git a/scwx-qt/gl/threshold.geom b/scwx-qt/gl/threshold.geom index dec09b01..53bde434 100644 --- a/scwx-qt/gl/threshold.geom +++ b/scwx-qt/gl/threshold.geom @@ -12,6 +12,7 @@ in VertexData vec3 texCoord; vec4 color; ivec2 timeRange; + bool displayed; } gsIn[]; smooth out vec3 texCoord; @@ -19,7 +20,8 @@ smooth out vec4 color; void main() { - if ((gsIn[0].threshold <= 0 || // If Threshold: 0 was specified, no threshold + if (gsIn[0].displayed && + (gsIn[0].threshold <= 0 || // If Threshold: 0 was specified, no threshold gsIn[0].threshold >= uMapDistance || // If Threshold is above current map distance gsIn[0].threshold >= 999) && // If Threshold: 999 was specified (or greater), no threshold (gsIn[0].timeRange[0] == 0 || // If there is no start time specified diff --git a/scwx-qt/source/scwx/qt/gl/draw/icons.cpp b/scwx-qt/source/scwx/qt/gl/draw/icons.cpp index d2c3d709..39dbd9ad 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/icons.cpp +++ b/scwx-qt/source/scwx/qt/gl/draw/icons.cpp @@ -7,6 +7,7 @@ #include #include +#include namespace scwx { @@ -24,7 +25,7 @@ static constexpr std::size_t kNumRectangles = 1; static constexpr std::size_t kNumTriangles = kNumRectangles * 2; static constexpr std::size_t kVerticesPerTriangle = 3; static constexpr std::size_t kVerticesPerRectangle = kVerticesPerTriangle * 2; -static constexpr std::size_t kPointsPerVertex = 9; +static constexpr std::size_t kPointsPerVertex = 10; static constexpr std::size_t kPointsPerTexCoord = 3; static constexpr std::size_t kIconBufferLength = kNumTriangles * kVerticesPerTriangle * kPointsPerVertex; @@ -34,12 +35,15 @@ static constexpr std::size_t kTextureBufferLength = struct IconDrawItem : types::EventHandler { boost::gil::rgba32f_pixel_t modulate_ {1.0f, 1.0f, 1.0f, 1.0f}; + bool visible_ {true}; double x_ {}; double y_ {}; units::degrees angle_ {}; std::string iconSheet_ {}; std::size_t iconIndex_ {}; std::string hoverText_ {}; + + std::shared_ptr iconInfo_ {}; }; class Icons::Impl @@ -67,9 +71,14 @@ public: ~Impl() {} - void UpdateBuffers(); - void UpdateTextureBuffer(); - void Update(bool textureAtlasChanged); + void UpdateBuffers(); + static void UpdateSingleBuffer(const std::shared_ptr& di, + std::size_t iconIndex, + std::vector& iconBuffer, + std::vector& hoverIcons); + void UpdateTextureBuffer(); + void UpdateModifiedIconBuffers(); + void Update(bool textureAtlasChanged); std::shared_ptr context_; @@ -77,6 +86,8 @@ public: bool dirty_ {false}; bool lastTextureAtlasChanged_ {false}; + boost::unordered_flat_set> dirtyIcons_ {}; + std::mutex iconMutex_; boost::unordered_flat_map> @@ -120,6 +131,7 @@ void Icons::Initialize() p->shaderProgram_ = p->context_->GetShaderProgram( {{GL_VERTEX_SHADER, ":/gl/texture2d_array.vert"}, + {GL_GEOMETRY_SHADER, ":/gl/threshold.geom"}, {GL_FRAGMENT_SHADER, ":/gl/texture2d_array.frag"}}); p->uMVPMatrixLocation_ = p->shaderProgram_->GetUniformLocation("uMVPMatrix"); @@ -167,6 +179,15 @@ void Icons::Initialize() reinterpret_cast(8 * sizeof(float))); gl.glEnableVertexAttribArray(4); + // aAngle + gl.glVertexAttribPointer(5, + 1, + GL_FLOAT, + GL_FALSE, + kPointsPerVertex * sizeof(float), + reinterpret_cast(9 * sizeof(float))); + gl.glEnableVertexAttribArray(5); + gl.glBindBuffer(GL_ARRAY_BUFFER, p->vbo_[1]); gl.glBufferData(GL_ARRAY_BUFFER, 0u, nullptr, GL_DYNAMIC_DRAW); @@ -292,12 +313,20 @@ std::shared_ptr Icons::AddIcon() return p->newIconList_.emplace_back(std::make_shared()); } +void Icons::SetIconVisible(const std::shared_ptr& di, + bool visible) +{ + di->visible_ = visible; + p->dirtyIcons_.insert(di); +} + void Icons::SetIconTexture(const std::shared_ptr& di, const std::string& iconSheet, std::size_t iconIndex) { di->iconSheet_ = iconSheet; di->iconIndex_ = iconIndex; + p->dirtyIcons_.insert(di); } void Icons::SetIconLocation(const std::shared_ptr& di, @@ -306,12 +335,14 @@ void Icons::SetIconLocation(const std::shared_ptr& di, { di->x_ = x; di->y_ = y; + p->dirtyIcons_.insert(di); } void Icons::SetIconAngle(const std::shared_ptr& di, units::angle::degrees angle) { di->angle_ = angle; + p->dirtyIcons_.insert(di); } void Icons::SetIconModulate(const std::shared_ptr& di, @@ -321,18 +352,21 @@ void Icons::SetIconModulate(const std::shared_ptr& di, modulate[1] / 255.0f, modulate[2] / 255.0f, modulate[3] / 255.0f}; + p->dirtyIcons_.insert(di); } void Icons::SetIconModulate(const std::shared_ptr& di, boost::gil::rgba32f_pixel_t modulate) { di->modulate_ = modulate; + p->dirtyIcons_.insert(di); } void Icons::SetIconHoverText(const std::shared_ptr& di, const std::string& text) { di->hoverText_ = text; + p->dirtyIcons_.insert(di); } void Icons::FinishIcons() @@ -374,7 +408,8 @@ void Icons::Impl::UpdateBuffers() continue; } - auto& icon = it->second; + auto& icon = it->second; + di->iconInfo_ = icon; // Validate icon if (di->iconIndex_ >= icon->numIcons_) @@ -387,61 +422,115 @@ void Icons::Impl::UpdateBuffers() // Icon is valid, add to valid icon list newValidIconList_.push_back(di); - // Base X/Y offsets in pixels - const float x = static_cast(di->x_); - const float y = static_cast(di->y_); + // Update icon buffer + UpdateSingleBuffer( + di, newValidIconList_.size() - 1, newIconBuffer_, newHoverIcons_); + } - // Icon size - const float iw = static_cast(icon->iconWidth_); - const float ih = static_cast(icon->iconHeight_); + // All icons have been updated + dirtyIcons_.clear(); +} - // Hot X/Y (zero-based icon center) - const float hx = static_cast(icon->hotX_); - const float hy = static_cast(icon->hotY_); +void Icons::Impl::UpdateSingleBuffer(const std::shared_ptr& di, + std::size_t iconIndex, + std::vector& iconBuffer, + std::vector& hoverIcons) +{ + auto& icon = di->iconInfo_; - // Final X/Y offsets in pixels - const float lx = std::roundf(-hx); - const float rx = std::roundf(lx + iw); - const float ty = std::roundf(+hy); - const float by = std::roundf(ty - ih); + // Base X/Y offsets in pixels + const float x = static_cast(di->x_); + const float y = static_cast(di->y_); - // Angle in degrees - units::angle::degrees angle = di->angle_; - const float a = angle.value(); + // Icon size + const float iw = static_cast(icon->iconWidth_); + const float ih = static_cast(icon->iconHeight_); - // Modulate color - const float mc0 = di->modulate_[0]; - const float mc1 = di->modulate_[1]; - const float mc2 = di->modulate_[2]; - const float mc3 = di->modulate_[3]; + // Hot X/Y (zero-based icon center) + const float hx = static_cast(icon->hotX_); + const float hy = static_cast(icon->hotY_); - newIconBuffer_.insert(newIconBuffer_.end(), - { - // Icon - x, y, lx, by, mc0, mc1, mc2, mc3, a, // BL - x, y, lx, ty, mc0, mc1, mc2, mc3, a, // TL - x, y, rx, by, mc0, mc1, mc2, mc3, a, // BR - x, y, rx, by, mc0, mc1, mc2, mc3, a, // BR - x, y, rx, ty, mc0, mc1, mc2, mc3, a, // TR - x, y, lx, ty, mc0, mc1, mc2, mc3, a // TL - }); + // Final X/Y offsets in pixels + const float lx = std::roundf(-hx); + const float rx = std::roundf(lx + iw); + const float ty = std::roundf(+hy); + const float by = std::roundf(ty - ih); - if (!di->hoverText_.empty() || di->event_ != nullptr) + // Angle in degrees + units::angle::degrees angle = di->angle_; + const float a = angle.value(); + + // Modulate color + const float mc0 = di->modulate_[0]; + const float mc1 = di->modulate_[1]; + const float mc2 = di->modulate_[2]; + const float mc3 = di->modulate_[3]; + + // Visibility + const float v = static_cast(di->visible_); + + // Icon initializer list data + const auto iconData = { + // Icon + x, y, lx, by, mc0, mc1, mc2, mc3, a, v, // BL + x, y, lx, ty, mc0, mc1, mc2, mc3, a, v, // TL + x, y, rx, by, mc0, mc1, mc2, mc3, a, v, // BR + x, y, rx, by, mc0, mc1, mc2, mc3, a, v, // BR + x, y, rx, ty, mc0, mc1, mc2, mc3, a, v, // TR + x, y, lx, ty, mc0, mc1, mc2, mc3, a, v // TL + }; + + // Buffer position data + auto iconBufferPosition = iconBuffer.end(); + auto iconBufferOffset = iconIndex * kIconBufferLength; + + if (iconBufferOffset < iconBuffer.size()) + { + iconBufferPosition = iconBuffer.begin() + iconBufferOffset; + } + + if (iconBufferPosition == iconBuffer.cend()) + { + iconBuffer.insert(iconBufferPosition, iconData); + } + else + { + std::copy(iconData.begin(), iconData.end(), iconBufferPosition); + } + + auto hoverIt = std::find_if(hoverIcons.begin(), + hoverIcons.end(), + [&di](auto& entry) { return entry.di_ == di; }); + + if (di->visible_ && (!di->hoverText_.empty() || di->event_ != nullptr)) + { + const units::angle::radians radians = angle; + + const float cosAngle = cosf(static_cast(radians.value())); + const float sinAngle = sinf(static_cast(radians.value())); + + const glm::mat2 rotate {cosAngle, -sinAngle, sinAngle, cosAngle}; + + const glm::vec2 otl = rotate * glm::vec2 {lx, ty}; + const glm::vec2 otr = rotate * glm::vec2 {rx, ty}; + const glm::vec2 obl = rotate * glm::vec2 {lx, by}; + const glm::vec2 obr = rotate * glm::vec2 {rx, by}; + + if (hoverIt == hoverIcons.end()) { - const units::angle::radians radians = angle; - - const float cosAngle = cosf(static_cast(radians.value())); - const float sinAngle = sinf(static_cast(radians.value())); - - const glm::mat2 rotate {cosAngle, -sinAngle, sinAngle, cosAngle}; - - const glm::vec2 otl = rotate * glm::vec2 {lx, ty}; - const glm::vec2 otr = rotate * glm::vec2 {rx, ty}; - const glm::vec2 obl = rotate * glm::vec2 {lx, by}; - const glm::vec2 obr = rotate * glm::vec2 {rx, by}; - - newHoverIcons_.emplace_back(IconHoverEntry {di, otl, otr, obl, obr}); + hoverIcons.emplace_back(IconHoverEntry {di, otl, otr, obl, obr}); } + else + { + hoverIt->otl_ = otl; + hoverIt->otr_ = otr; + hoverIt->obl_ = obl; + hoverIt->obr_ = obr; + } + } + else if (hoverIt != hoverIcons.end()) + { + hoverIcons.erase(hoverIt); } } @@ -533,10 +622,40 @@ void Icons::Impl::UpdateTextureBuffer() } } +void Icons::Impl::UpdateModifiedIconBuffers() +{ + // Update buffers for modified icons + for (auto& di : dirtyIcons_) + { + // Find modified icon in the current list + auto it = + std::find(currentIconList_.cbegin(), currentIconList_.cend(), di); + + // Ignore invalid icons + if (it == currentIconList_.cend()) + { + continue; + } + + auto iconIndex = std::distance(currentIconList_.cbegin(), it); + + UpdateSingleBuffer(di, iconIndex, currentIconBuffer_, currentHoverIcons_); + } + + // Clear list of modified icons + if (!dirtyIcons_.empty()) + { + dirtyIcons_.clear(); + dirty_ = true; + } +} + void Icons::Impl::Update(bool textureAtlasChanged) { gl::OpenGLFunctions& gl = context_->gl(); + UpdateModifiedIconBuffers(); + // If the texture atlas has changed if (dirty_ || textureAtlasChanged || lastTextureAtlasChanged_) { diff --git a/scwx-qt/source/scwx/qt/gl/draw/icons.hpp b/scwx-qt/source/scwx/qt/gl/draw/icons.hpp index f9e4c91c..3041a962 100644 --- a/scwx-qt/source/scwx/qt/gl/draw/icons.hpp +++ b/scwx-qt/source/scwx/qt/gl/draw/icons.hpp @@ -96,6 +96,12 @@ public: */ std::shared_ptr AddIcon(); + /** + * @param [in] di Icon draw item + * @param [in] visible Visibility of the icon + */ + void SetIconVisible(const std::shared_ptr& di, bool visible); + /** * Sets the texture of an icon. * @@ -103,9 +109,9 @@ public: * @param [in] iconSheet The name of the icon sheet in the texture atlas * @param [in] iconIndex The zero-based index of the icon in the icon sheet */ - static void SetIconTexture(const std::shared_ptr& di, - const std::string& iconSheet, - std::size_t iconIndex); + void SetIconTexture(const std::shared_ptr& di, + const std::string& iconSheet, + std::size_t iconIndex); /** * Sets the location of an icon. @@ -114,7 +120,7 @@ public: * @param [in] x The x location of the icon in pixels. * @param [in] y The y location of the icon in pixels. */ - static void + void SetIconLocation(const std::shared_ptr& di, double x, double y); /** @@ -123,8 +129,8 @@ public: * @param [in] di Icon draw item * @param [in] angle Angle in degrees */ - static void SetIconAngle(const std::shared_ptr& di, - units::angle::degrees angle); + void SetIconAngle(const std::shared_ptr& di, + units::angle::degrees angle); /** * Sets the modulate color of an icon. @@ -132,8 +138,8 @@ public: * @param [in] di Icon draw item * @param [in] modulate Modulate color */ - static void SetIconModulate(const std::shared_ptr& di, - boost::gil::rgba8_pixel_t modulate); + void SetIconModulate(const std::shared_ptr& di, + boost::gil::rgba8_pixel_t modulate); /** * Sets the modulate color of an icon. @@ -141,8 +147,8 @@ public: * @param [in] di Icon draw item * @param [in] modulate Modulate color */ - static void SetIconModulate(const std::shared_ptr& di, - boost::gil::rgba32f_pixel_t modulate); + void SetIconModulate(const std::shared_ptr& di, + boost::gil::rgba32f_pixel_t modulate); /** * Sets the hover text of an icon. @@ -150,8 +156,8 @@ public: * @param [in] di Icon draw item * @param [in] text Hover text */ - static void SetIconHoverText(const std::shared_ptr& di, - const std::string& text); + void SetIconHoverText(const std::shared_ptr& di, + const std::string& text); /** * Finalizes the draw item after adding new icons. diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp index 52e1418c..d00fb717 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -74,7 +75,6 @@ public: types::GetTextureName(types::ImageTexture::MapTilerLogo)}; std::shared_ptr compassIcon_ {}; - bool compassIconDirty_ {false}; double lastBearing_ {0.0}; std::shared_ptr mapLogoIcon_ {}; @@ -147,8 +147,7 @@ void OverlayLayer::Initialize() p->icons_->StartIcons(); p->compassIcon_ = p->icons_->AddIcon(); - gl::draw::Icons::SetIconTexture( - p->compassIcon_, p->cardinalPointIconName_, 0); + p->icons_->SetIconTexture(p->compassIcon_, p->cardinalPointIconName_, 0); gl::draw::Icons::RegisterEventHandler( p->compassIcon_, [this](QEvent* ev) @@ -157,18 +156,16 @@ void OverlayLayer::Initialize() { case QEvent::Type::Enter: // Highlight icon on mouse enter - gl::draw::Icons::SetIconModulate( + p->icons_->SetIconModulate( p->compassIcon_, boost::gil::rgba32f_pixel_t {1.5f, 1.5f, 1.5f, 1.0f}); - p->compassIconDirty_ = true; break; case QEvent::Type::Leave: // Restore icon on mouse leave - gl::draw::Icons::SetIconModulate( + p->icons_->SetIconModulate( p->compassIcon_, boost::gil::rgba32f_pixel_t {1.0f, 1.0f, 1.0f, 1.0f}); - p->compassIconDirty_ = true; break; case QEvent::Type::MouseButtonPress: @@ -196,13 +193,11 @@ void OverlayLayer::Initialize() p->mapLogoIcon_ = p->icons_->AddIcon(); if (context()->map_provider() == MapProvider::Mapbox) { - gl::draw::Icons::SetIconTexture( - p->mapLogoIcon_, p->mapboxLogoImageName_, 0); + p->icons_->SetIconTexture(p->mapLogoIcon_, p->mapboxLogoImageName_, 0); } else if (context()->map_provider() == MapProvider::MapTiler) { - gl::draw::Icons::SetIconTexture( - p->mapLogoIcon_, p->mapTilerLogoImageName_, 0); + p->icons_->SetIconTexture(p->mapLogoIcon_, p->mapTilerLogoImageName_, 0); } p->icons_->FinishIcons(); @@ -283,42 +278,29 @@ void OverlayLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) ImGui::GetFontSize() != p->lastFontSize_) { // Set the compass icon in the upper right, below the sweep time window - gl::draw::Icons::SetIconLocation(p->compassIcon_, - params.width - 24, - params.height - - (ImGui::GetFontSize() + 32)); - p->compassIconDirty_ = true; + p->icons_->SetIconLocation(p->compassIcon_, + params.width - 24, + params.height - (ImGui::GetFontSize() + 32)); } if (params.bearing != p->lastBearing_) { if (params.bearing == 0.0) { // Use cardinal point icon when bearing is oriented north-up - gl::draw::Icons::SetIconTexture( + p->icons_->SetIconTexture( p->compassIcon_, p->cardinalPointIconName_, 0); - gl::draw::Icons::SetIconAngle(p->compassIcon_, - units::angle::degrees {0.0}); + p->icons_->SetIconAngle(p->compassIcon_, + units::angle::degrees {0.0}); } else { // Use rotated compass icon when bearing is rotated away from north-up - gl::draw::Icons::SetIconTexture( - p->compassIcon_, p->compassIconName_, 0); - gl::draw::Icons::SetIconAngle( + p->icons_->SetIconTexture(p->compassIcon_, p->compassIconName_, 0); + p->icons_->SetIconAngle( p->compassIcon_, units::angle::degrees {-45 - params.bearing}); } - - // Mark icon for re-drawing - p->compassIconDirty_ = true; } - if (p->compassIconDirty_) - { - // Update icon render buffers - p->icons_->FinishIcons(); - } - - DrawLayer::Render(params); if (radarProductView != nullptr) { @@ -381,18 +363,25 @@ void OverlayLayer::Render(const QMapLibre::CustomLayerRenderParameters& params) ImGui::End(); } + auto& generalSettings = settings::GeneralSettings::Instance(); + QMargins colorTableMargins = context()->color_table_margins(); if (colorTableMargins != p->lastColorTableMargins_ || p->firstRender_) { // Draw map logo with a 10x10 indent from the bottom left - gl::draw::Icons::SetIconLocation(p->mapLogoIcon_, - 10 + colorTableMargins.left(), - 10 + colorTableMargins.bottom()); + p->icons_->SetIconLocation(p->mapLogoIcon_, + 10 + colorTableMargins.left(), + 10 + colorTableMargins.bottom()); p->icons_->FinishIcons(); } + p->icons_->SetIconVisible(p->mapLogoIcon_, + generalSettings.show_map_logo().GetValue()); + + DrawLayer::Render(params); auto mapCopyrights = context()->map_copyrights(); - if (mapCopyrights.length() > 0) + if (mapCopyrights.length() > 0 && + generalSettings.show_map_attribution().GetValue()) { auto attributionFont = manager::FontManager::Instance().GetImGuiFont( types::FontCategory::Attribution); From 35bd2433a71021017a84593bc85031e4324c853a Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 8 Mar 2024 00:55:55 -0600 Subject: [PATCH 33/33] Update map immediately if map logo or attribution is toggled --- scwx-qt/source/scwx/qt/map/overlay_layer.cpp | 30 ++++++++++++++++++-- scwx-qt/source/scwx/qt/map/overlay_layer.hpp | 2 ++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp index d00fb717..1f1844fd 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.cpp @@ -42,14 +42,38 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class OverlayLayerImpl { public: - explicit OverlayLayerImpl(std::shared_ptr context) : + explicit OverlayLayerImpl(OverlayLayer* self, + std::shared_ptr context) : + self_ {self}, activeBoxOuter_ {std::make_shared(context)}, activeBoxInner_ {std::make_shared(context)}, geoIcons_ {std::make_shared(context)}, icons_ {std::make_shared(context)} { + auto& generalSettings = settings::GeneralSettings::Instance(); + + showMapAttributionCallbackUuid_ = + generalSettings.show_map_attribution().RegisterValueChangedCallback( + [this](const bool&) { Q_EMIT self_->NeedsRendering(); }); + showMapLogoCallbackUuid_ = + generalSettings.show_map_logo().RegisterValueChangedCallback( + [this](const bool&) { Q_EMIT self_->NeedsRendering(); }); } - ~OverlayLayerImpl() = default; + + ~OverlayLayerImpl() + { + auto& generalSettings = settings::GeneralSettings::Instance(); + + generalSettings.show_map_attribution().UnregisterValueChangedCallback( + showMapAttributionCallbackUuid_); + generalSettings.show_map_logo().UnregisterValueChangedCallback( + showMapLogoCallbackUuid_); + } + + OverlayLayer* self_; + + boost::uuids::uuid showMapAttributionCallbackUuid_; + boost::uuids::uuid showMapLogoCallbackUuid_; std::shared_ptr positionManager_ { manager::PositionManager::Instance()}; @@ -91,7 +115,7 @@ public: }; OverlayLayer::OverlayLayer(std::shared_ptr context) : - DrawLayer(context), p(std::make_unique(context)) + DrawLayer(context), p(std::make_unique(this, context)) { AddDrawItem(p->activeBoxOuter_); AddDrawItem(p->activeBoxInner_); diff --git a/scwx-qt/source/scwx/qt/map/overlay_layer.hpp b/scwx-qt/source/scwx/qt/map/overlay_layer.hpp index 411694b1..f842e81b 100644 --- a/scwx-qt/source/scwx/qt/map/overlay_layer.hpp +++ b/scwx-qt/source/scwx/qt/map/overlay_layer.hpp @@ -13,6 +13,8 @@ class OverlayLayerImpl; class OverlayLayer : public DrawLayer { + Q_DISABLE_COPY_MOVE(OverlayLayer) + public: explicit OverlayLayer(std::shared_ptr context); ~OverlayLayer();