From 23541920100b4b07a0b2b01034c6d3f1b6fccbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Kubern=C3=A1t?= Date: Thu, 10 Aug 2023 16:06:45 +0200 Subject: [PATCH] Add a demo map viewer for QtWidgets --- Demos/CMakeLists.txt | 5 +- Demos/meson.build | 9 +++ Demos/src/QtWidgetsDemoApp.cpp | 114 +++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 Demos/src/QtWidgetsDemoApp.cpp diff --git a/Demos/CMakeLists.txt b/Demos/CMakeLists.txt index 53bc0a3af..857b0915b 100644 --- a/Demos/CMakeLists.txt +++ b/Demos/CMakeLists.txt @@ -210,8 +210,11 @@ if(${OSMSCOUT_BUILD_CLIENT_QT}) COMMAND Qt5::windeployqt --dir "${CMAKE_BINARY_DIR}/windeployqt" "$/$" ) endif() + + #---- QtWidgetsDemoApp + osmscout_demo_project(NAME QtWidgetsDemoApp SOURCES src/QtWidgetsDemoApp.cpp TARGET OSMScout::ClientQt) else() - message("Skip ElevationProfileChart, NavigationSimulation and RoutingParameters demo, libosmscout-client-qt is missing.") + message("Skip ElevationProfileChart, NavigationSimulation and RoutingParameters QtWidgetsDemoApp demo, libosmscout-client-qt is missing.") endif() #---- DrawMapSVG diff --git a/Demos/meson.build b/Demos/meson.build index 9b1040d1b..ee6d87a6f 100644 --- a/Demos/meson.build +++ b/Demos/meson.build @@ -170,6 +170,15 @@ if buildClientQt override_options : ['unity=off'], # generated code for qt resources use static variables with the same name install: true, install_dir: demoInstallDir) + + QtWidgetsDemoApp = executable('QtWidgetsDemoApp', + ['src/QtWidgetsDemoApp.cpp'], + cpp_args: ['-fPIC'], + include_directories: [osmscoutIncDir, osmscoutmapIncDir, osmscoutmapqtIncDir, osmscoutclientIncDir, osmscoutclientqtIncDir], + dependencies: [qtClientDep], + link_with: [osmscout, osmscoutmap, osmscoutmapqt, osmscoutclientqt], + install: true, + install_dir: demoInstallDir) endif Routing = executable('Routing', diff --git a/Demos/src/QtWidgetsDemoApp.cpp b/Demos/src/QtWidgetsDemoApp.cpp new file mode 100644 index 000000000..25d15eb47 --- /dev/null +++ b/Demos/src/QtWidgetsDemoApp.cpp @@ -0,0 +1,114 @@ +#include +#include + +#include + +const auto MAX_ZOOM = 20; +const auto MIN_ZOOM = 0; +const auto MAP_DPI = 96; + +namespace { +template +auto pos(EventType* event) +{ +#if QT_VERSION < 0x051400 + return event->pos(); +#else + return event->position().toPoint(); +#endif +} +} + +class MapFrame : public QWidget { +public: + explicit MapFrame(const QString& maps_dir, const QString& stylesheet_file) + { + m_currentProjection.Set({0, 0}, 0.0, osmscout::Magnification{osmscout::Magnification::magWorld}, MAP_DPI, width(), height()); + + QFileInfo stylesheetFile(stylesheet_file); + if (!osmscout::OSMScoutQt::NewInstance() + .WithMapLookupDirectories({maps_dir}) + .WithStyleSheetDirectory(stylesheetFile.dir().path()) + .WithStyleSheetFile(stylesheetFile.fileName()) + .Init()) { + throw std::runtime_error{"failed to init OSMScoutQt"}; + } + + m_renderer = osmscout::OSMScoutQt::GetInstance().MakeMapRenderer(osmscout::RenderingType::TiledRendering); + connect(m_renderer, &osmscout::MapRenderer::Redraw, this, [this] {update();}); + } + +protected: + void paintEvent(QPaintEvent*) override + { + auto painter = QPainter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setRenderHint(QPainter::TextAntialiasing, true); + painter.setRenderHint(QPainter::SmoothPixmapTransform, true); + + m_renderer->RenderMap(painter, osmscout::MapViewStruct{ + m_currentProjection.GetCenter(), + osmscout::Bearing{}, + m_currentProjection.GetMagnification(), + static_cast(width()), + static_cast(height()), + MAP_DPI, + }); + } + + void mousePressEvent(QMouseEvent* ev) override + { + m_lastMousePos = ::pos(ev); + } + + void mouseMoveEvent(QMouseEvent* ev) override + { + auto x_delta = ::pos(ev).x() - m_lastMousePos.x(); + auto y_delta = ::pos(ev).y() - m_lastMousePos.y(); + m_currentProjection.Move(-x_delta, y_delta); + m_lastMousePos = ::pos(ev); + update(); + } + + void wheelEvent(QWheelEvent* ev) override + { + auto magnification = m_currentProjection.GetMagnification().GetLevel(); + if (ev->angleDelta().y() > 0) { + if (magnification >= MAX_ZOOM) { + return; + } + magnification++; + auto x_delta = (width() / 2. - ::pos(ev).x()) * 0.75; + auto y_delta = (height() / 2. - ::pos(ev).y()) * 0.75; + m_currentProjection.Move(-x_delta, y_delta); + } else { + if (magnification <= MIN_ZOOM) { + return; + } + magnification--; + auto x_delta = (width() / 2. - ::pos(ev).x()) * 0.75; + auto y_delta = (height() / 2. - ::pos(ev).y()) * 0.75; + m_currentProjection.Move(x_delta, -y_delta); + } + m_currentProjection.Set(m_currentProjection.GetCenter(), osmscout::Magnification{osmscout::MagnificationLevel{magnification}}, width(), height()); + update(); + } + +private: + osmscout::MapRenderer* m_renderer; + osmscout::MercatorProjection m_currentProjection; + QPoint m_lastMousePos; +}; + +int main(int argc, char *argv[]) +{ + if (argc != 3) { + std::cerr << "Usage: " << argv[0] << ": \n"; + return 1; + } + osmscout::OSMScoutQt::RegisterQmlTypes(); + QApplication app(argc, argv); + MapFrame map(argv[1], argv[2]); + map.show(); + return QApplication::exec(); +}