File indexing completed on 2024-04-28 04:41:02

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <KOSMIndoorMap/FloorLevelModel>
0008 #include <KOSMIndoorMap/HitDetector>
0009 #include <KOSMIndoorMap/MapCSSParser>
0010 #include <KOSMIndoorMap/MapCSSStyle>
0011 #include <KOSMIndoorMap/MapData>
0012 #include <KOSMIndoorMap/MapLoader>
0013 #include <KOSMIndoorMap/PainterRenderer>
0014 #include <KOSMIndoorMap/SceneController>
0015 #include <KOSMIndoorMap/SceneGraph>
0016 #include <KOSMIndoorMap/View>
0017 
0018 #include <QApplication>
0019 #include <QCommandLineParser>
0020 #include <QMouseEvent>
0021 #include <QComboBox>
0022 #include <QHBoxLayout>
0023 #include <QPainter>
0024 #include <QRegularExpression>
0025 #include <QtPlugin>
0026 
0027 #if HAVE_OSM_PBF_SUPPORT
0028 Q_IMPORT_PLUGIN(OSM_PbfIOPlugin)
0029 #endif
0030 Q_IMPORT_PLUGIN(OSM_XmlIOPlugin)
0031 
0032 using namespace KOSMIndoorMap;
0033 
0034 static QString cssPath(const QString &styleName)
0035 {
0036     return QLatin1String(SOURCE_DIR "/../src/map/assets/css/") + styleName + QLatin1String(".mapcss");
0037 //     return QLatin1String(":/org.kde.kosmindoormap/assets/css/") + styleName + QLatin1String(".mapcss");
0038 }
0039 
0040 class MapWidget : public QWidget
0041 {
0042 public:
0043     explicit MapWidget(QWidget *parent = nullptr);
0044     void paintEvent(QPaintEvent *event) override;
0045     void resizeEvent(QResizeEvent *event) override;
0046     void mousePressEvent(QMouseEvent *event) override;
0047     void mouseMoveEvent(QMouseEvent *event) override;
0048     void mouseReleaseEvent(QMouseEvent *event) override;
0049     void wheelEvent(QWheelEvent *event) override;
0050     void setMapData(MapData &&data);
0051     void setStyleSheet(const QString &styleName);
0052 
0053     MapData m_data;
0054     SceneGraph m_sg;
0055     MapCSSStyle m_style;
0056     SceneController m_controller;
0057     PainterRenderer m_renderer;
0058     View m_view;
0059     QPoint m_lastPanPoint;
0060 };
0061 
0062 MapWidget::MapWidget(QWidget* parent)
0063     : QWidget(parent)
0064 {
0065     m_view.setScreenSize(size());
0066     m_controller.setView(&m_view);
0067 }
0068 
0069 void MapWidget::paintEvent(QPaintEvent *event)
0070 {
0071     m_controller.updateScene(m_sg);
0072     QPainter p(this);
0073     m_renderer.setPainter(&p);
0074     m_renderer.render(m_sg, &m_view);
0075     return QWidget::paintEvent(event);
0076 }
0077 
0078 void MapWidget::resizeEvent(QResizeEvent *event)
0079 {
0080     QWidget::resizeEvent(event);
0081     m_view.setScreenSize(size());
0082 }
0083 
0084 void MapWidget::mousePressEvent(QMouseEvent *event)
0085 {
0086     m_lastPanPoint = event->pos();
0087     QWidget::mousePressEvent(event);
0088 }
0089 
0090 void MapWidget::mouseMoveEvent(QMouseEvent *event)
0091 {
0092     m_view.panScreenSpace(m_lastPanPoint - event->pos());
0093     m_lastPanPoint = event->pos();
0094     QWidget::mouseMoveEvent(event);
0095     update();
0096 }
0097 
0098 void MapWidget::mouseReleaseEvent(QMouseEvent *event)
0099 {
0100     if (event->button() == Qt::RightButton) {
0101         HitDetector detector;
0102         const auto items = detector.itemsAt(event->pos(), m_sg, &m_view);
0103         for (const auto item : items) {
0104             qDebug() << item->element.url();
0105             for (auto it = item->element.tagsBegin(); it != item->element.tagsEnd(); ++it) {
0106                 qDebug() << "    " << (*it).key.name() << (*it).value;
0107             }
0108             switch (item->element.type()) {
0109                 case OSM::Type::Null:
0110                 case OSM::Type::Node:
0111                     break;
0112                 case OSM::Type::Way:
0113                     for (const auto &node : item->element.way()->nodes) {
0114                         qDebug() << "      " << node;
0115                     }
0116                     break;
0117                 case OSM::Type::Relation:
0118                     for (const auto &mem : item->element.relation()->members) {
0119                         qDebug() << "      " << mem.role().name() << (int)mem.type() << mem.id;
0120                     }
0121                     break;
0122             }
0123         }
0124     }
0125 }
0126 
0127 void MapWidget::wheelEvent(QWheelEvent *event)
0128 {
0129     if (event->angleDelta().y() > 0) {
0130         m_view.zoomIn(event->position());
0131     } else {
0132         m_view.zoomOut(event->position());
0133     }
0134     QWidget::wheelEvent(event);
0135     update();
0136 }
0137 
0138 void MapWidget::setMapData(MapData &&data)
0139 {
0140     m_data = std::move(data);
0141     m_controller.setMapData(m_data);
0142     m_view.setSceneBoundingBox(m_data.boundingBox());
0143     m_style.compile(m_data.dataSet());
0144     m_controller.setStyleSheet(&m_style);
0145     update();
0146 }
0147 
0148 void MapWidget::setStyleSheet(const QString &styleName)
0149 {
0150     MapCSSParser cssParser;
0151     m_style = cssParser.parse(cssPath(styleName));
0152     m_style.compile(m_data.dataSet());
0153     m_controller.setStyleSheet(&m_style);
0154 }
0155 
0156 
0157 int main(int argc, char **argv)
0158 {
0159     QApplication app(argc, argv);
0160     QCommandLineParser parser;
0161     QCommandLineOption coordOpt({QStringLiteral("coordinate"), QStringLiteral("c")}, QStringLiteral("coordinate of the location to load"), QStringLiteral("lat,lon"));
0162     parser.addOption(coordOpt);
0163     QCommandLineOption fileOpt({QStringLiteral("file"), QStringLiteral("f")}, QStringLiteral("O5M or OSM PBF file to load"), QStringLiteral("file"));
0164     parser.addOption(fileOpt);
0165     parser.addHelpOption();
0166     parser.addVersionOption();
0167     parser.process(app);
0168 
0169     MapWidget widget;
0170     widget.resize(480, 720);
0171     widget.setStyleSheet(QStringLiteral("breeze-light"));
0172 
0173     auto layout = new QHBoxLayout(&widget);
0174     layout->setAlignment(Qt::AlignTop);
0175 
0176     FloorLevelModel floorModel;
0177     auto levelBox = new QComboBox;
0178     levelBox->setModel(&floorModel);
0179     layout->addWidget(levelBox);
0180     QObject::connect(levelBox, &QComboBox::currentTextChanged, &app, [&]() {
0181         widget.m_view.setLevel(levelBox->currentData().value<MapLevel>().numericLevel());
0182         widget.update();
0183     });
0184 
0185     auto styleBox = new QComboBox;
0186     layout->addWidget(styleBox);
0187     styleBox->addItems({QStringLiteral("breeze-light"), QStringLiteral("breeze-dark"), QStringLiteral("diagnostic")});
0188     QObject::connect(styleBox, &QComboBox::currentTextChanged, &app, [&](const QString &styleName) {
0189         widget.setStyleSheet(styleName);
0190         widget.update();
0191     });
0192 
0193     widget.show();
0194 
0195     MapLoader loader;
0196     QObject::connect(&loader, &MapLoader::done, &app, [&]() {
0197         widget.setMapData(loader.takeData());
0198         floorModel.setMapData(&widget.m_data);
0199         levelBox->setCurrentText(QLatin1String("0"));
0200     });
0201 
0202     if (parser.isSet(fileOpt)) {
0203         loader.loadFromFile(parser.value(fileOpt));
0204     } else if (parser.isSet(coordOpt)) {
0205         const auto s = parser.value(coordOpt).split(QRegularExpression(QStringLiteral("[,/;]")));
0206         loader.loadForCoordinate(s.at(0).toDouble(), s.at(1).toDouble());
0207     }
0208 
0209     return app.exec();
0210 }