diff --git a/src/map/scene/scenecontroller.h b/src/map/scene/scenecontroller.h index 7902501..bd6b3b7 100644 --- a/src/map/scene/scenecontroller.h +++ b/src/map/scene/scenecontroller.h @@ -1,93 +1,94 @@ /* Copyright (C) 2020 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef KOSMINDOORMAP_SCENECONTROLLER_H #define KOSMINDOORMAP_SCENECONTROLLER_H #include +#include #include #include "../style/mapcssresult.h" class QPolygonF; class QString; namespace OSM { class Element; } namespace KOSMIndoorMap { class MapData; class MapCSSStyle; class SceneGraph; class SceneGraphItem; class SceneGraphItemPayload; class View; /** Creates/updates the scene graph based on a given style sheet and view. */ class SceneController { public: explicit SceneController(); ~SceneController(); void setDataSet(const MapData *data); void setStyleSheet(const MapCSSStyle *styleSheet); void setView(const View *view); /** Creates or updates @p sg based on the currently set style and view settings. * When possible, provide the scene graph of the previous run to re-use scene graph elements that didn't change. */ void updateScene(SceneGraph &sg) const; private: void updateCanvas(SceneGraph &sg) const; void updateElement(OSM::Element e, int level, SceneGraph &sg) const; QPolygonF createPolygon(OSM::Element e) const; QPainterPath createPath(OSM::Element e, QPolygonF &outerPath) const; void applyGenericStyle(const MapCSSDeclaration *decl, SceneGraphItemPayload *item) const; void applyPenStyle(const MapCSSDeclaration *decl, QPen &pen, double &opacity) const; void applyCasingPenStyle(const MapCSSDeclaration *decl, QPen &pen, double &opacity) const; void applyFontStyle(const MapCSSDeclaration *decl, QFont &font) const; void initializePen(QPen &pen) const; void finalizePen(QPen &pen, double opacity) const; void addItem(SceneGraph &sg, OSM::Element e, int level, std::unique_ptr &&payload) const; const MapData *m_data = nullptr; const MapCSSStyle *m_styleSheet = nullptr; const View *m_view = nullptr; mutable MapCSSResult m_styleResult; mutable QColor m_defaultTextColor; mutable QFont m_defaultFont; mutable QPolygonF m_labelPlacementPath; OSM::TagKey m_layerTag; OSM::TagKey m_typeTag; mutable bool m_dirty = true; }; } #endif // KOSMINDOORMAP_SCENECONTROLLER_H diff --git a/tests/indoormap.cpp b/tests/indoormap.cpp index 9193017..fca575b 100644 --- a/tests/indoormap.cpp +++ b/tests/indoormap.cpp @@ -1,216 +1,224 @@ /* Copyright (C) 2020 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KOSMIndoorMap; static QString cssPath(const QString &styleName) { return QLatin1String(SOURCE_DIR "/../src/map/assets/css/") + styleName + QLatin1String(".mapcss"); // return QLatin1String(":/org.kde.kosmindoormap/assets/css/") + styleName + QLatin1String(".mapcss"); } class MapWidget : public QWidget { public: explicit MapWidget(QWidget *parent = nullptr); void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void wheelEvent(QWheelEvent *event) override; void setMapData(MapData &&data); void setStyleSheet(const QString &styleName); MapData m_data; SceneGraph m_sg; MapCSSStyle m_style; SceneController m_controller; PainterRenderer m_renderer; View m_view; QPoint m_lastPanPoint; }; MapWidget::MapWidget(QWidget* parent) : QWidget(parent) { m_view.setScreenSize(size()); m_controller.setView(&m_view); } void MapWidget::paintEvent(QPaintEvent *event) { m_controller.updateScene(m_sg); QPainter p(this); m_renderer.setPainter(&p); m_renderer.render(m_sg, &m_view); return QWidget::paintEvent(event); } void MapWidget::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); m_view.setScreenSize(size()); } void MapWidget::mousePressEvent(QMouseEvent *event) { m_lastPanPoint = event->pos(); QWidget::mousePressEvent(event); } void MapWidget::mouseMoveEvent(QMouseEvent *event) { m_view.panScreenSpace(m_lastPanPoint - event->pos()); m_lastPanPoint = event->pos(); QWidget::mouseMoveEvent(event); update(); } void MapWidget::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::RightButton) { HitDetector detector; const auto items = detector.itemsAt(event->pos(), m_sg, &m_view); for (const auto item : items) { qDebug() << item->element.url(); for (auto it = item->element.tagsBegin(); it != item->element.tagsEnd(); ++it) { qDebug() << " " << (*it).key.name() << (*it).value; } switch (item->element.type()) { case OSM::Type::Null: case OSM::Type::Node: break; case OSM::Type::Way: for (const auto &node : item->element.way()->nodes) { qDebug() << " " << node; } break; case OSM::Type::Relation: for (const auto &mem : item->element.relation()->members) { qDebug() << " " << mem.role << (int)mem.type << mem.id; } break; } } } } void MapWidget::wheelEvent(QWheelEvent *event) { if (event->angleDelta().y() > 0) { +#if QT_VERSION <= QT_VERSION_CHECK(5, 14, 0) + m_view.zoomIn(event->pos()); +#else m_view.zoomIn(event->position()); +#endif } else { +#if QT_VERSION <= QT_VERSION_CHECK(5, 14, 0) + m_view.zoomOut(event->pos()); +#else m_view.zoomOut(event->position()); +#endif } QWidget::wheelEvent(event); update(); } void MapWidget::setMapData(MapData &&data) { m_data = std::move(data); m_controller.setDataSet(&m_data); m_view.setSceneBoundingBox(m_data.boundingBox()); m_style.compile(m_data.dataSet()); m_controller.setStyleSheet(&m_style); update(); } void MapWidget::setStyleSheet(const QString &styleName) { MapCSSParser cssParser; m_style = cssParser.parse(cssPath(styleName)); m_style.compile(m_data.dataSet()); m_controller.setStyleSheet(&m_style); } int main(int argc, char **argv) { QApplication app(argc, argv); QCommandLineParser parser; QCommandLineOption coordOpt({QStringLiteral("coordinate"), QStringLiteral("c")}, QStringLiteral("coordinate of the location to load"), QStringLiteral("lat,lon")); parser.addOption(coordOpt); QCommandLineOption o5mOpt({QStringLiteral("o5m")}, QStringLiteral("o5m file to load"), QStringLiteral("o5m file")); parser.addOption(o5mOpt); parser.addHelpOption(); parser.addVersionOption(); parser.process(app); MapWidget widget; widget.resize(480, 720); widget.setStyleSheet(QStringLiteral("breeze-light")); auto layout = new QHBoxLayout(&widget); layout->setAlignment(Qt::AlignTop); auto levelBox = new QComboBox; layout->addWidget(levelBox); QObject::connect(levelBox, &QComboBox::currentTextChanged, &app, [&]() { widget.m_view.setLevel(levelBox->currentData().toInt()); widget.update(); }); auto styleBox = new QComboBox; layout->addWidget(styleBox); styleBox->addItems({QStringLiteral("breeze-light"), QStringLiteral("breeze-dark"), QStringLiteral("diagnostic")}); QObject::connect(styleBox, &QComboBox::currentTextChanged, &app, [&](const QString &styleName) { widget.setStyleSheet(styleName); widget.update(); }); widget.show(); MapLoader loader; QObject::connect(&loader, &MapLoader::done, &app, [&]() { widget.setMapData(loader.takeData()); levelBox->clear(); for (const auto &l : widget.m_data.m_levelMap) { if (l.first.isFullLevel()) { levelBox->addItem(l.first.name(), l.first.numericLevel()); } } levelBox->setCurrentText(QLatin1String("0")); }); if (parser.isSet(o5mOpt)) { loader.loadFromO5m(parser.value(o5mOpt)); } else if (parser.isSet(coordOpt)) { const auto s = parser.value(coordOpt).split(QRegularExpression(QStringLiteral("[,/;]"))); loader.loadForCoordinate(s.at(0).toDouble(), s.at(1).toDouble()); } return app.exec(); }