Commit 408f05d0 authored by Volker Krause's avatar Volker Krause
Browse files

Add proof-of-concept map integration for KPT rental vehicle live data

This shows colored icons and the number of available vehicles of e.g.
bike sharing stations.

There is a lot of work still to be done though, model updates aren't
handled, merging with rental station OSM base data doesn't happen yet,
etc.
parent e85d55a9
......@@ -4,6 +4,7 @@ if (BISON_FOUND AND FLEX_FOUND)
endif()
if (TARGET KOSMIndoorMap AND TARGET Qt5::Quick)
add_subdirectory(map-quick)
add_subdirectory(map-publictransport-integration)
endif()
if (NOT CROSS_COMPILING)
add_subdirectory(tools)
......
set(kosmindoormap_kpublictransport_integration_qml
qmldir
)
add_library(kosmindoormap_kpublictransport_integration_plugin
kosmindoormap-kpublictransport-integration.cpp
locationqueryoverlayproxymodel.cpp
)
target_link_libraries(kosmindoormap_kpublictransport_integration_plugin
Qt5::Qml
KOSMIndoorMap
KPublicTransport
)
# make examples work without installation
if (NOT CMAKE_VERSION VERSION_LESS 3.14)
set_property(TARGET kosmindoormap_kpublictransport_integration_plugin PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/org/kde/kosmindoormap/kpublictransport)
file(MAKE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/org/kde/kosmindoormap/kpublictransport/)
foreach(f IN LISTS kosmindoormap_kpublictransport_integration_qml)
file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/${f} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/org/kde/kosmindoormap/kpublictransport/${f} SYMBOLIC)
endforeach()
else()
message(WARNING "CMake is too old, cannot setup examples to work without installation")
endif()
install(TARGETS kosmindoormap_kpublictransport_integration_plugin DESTINATION ${QML_INSTALL_DIR}/org/kde/kosmindoormap/kpublictransport)
install(FILES ${kosmindoormap_kpublictransport_integration_qml} DESTINATION ${QML_INSTALL_DIR}/org/kde/kosmindoormap/kpublictransport)
/*
SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "kosmindoormap-kpublictransport-integration.h"
#include "locationqueryoverlayproxymodel.h"
#include <QQmlEngine>
using namespace KOSMIndoorMap;
void KOSMIndoorMapQuickPlugin::registerTypes(const char *uri)
{
Q_UNUSED(uri);
qmlRegisterType<LocationQueryOverlayProxyModel>("org.kde.kosmindoormap.kpublictransport", 1, 0, "LocationQueryOverlayProxyModel");
}
/*
SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KOSMINDOORMAP_KPUBLICTRANSPORT_PLUGIN_H
#define KOSMINDOORMAP_KPUBLICTRANSPORT_PLUGIN_H
#include <QQmlExtensionPlugin>
/** Plugin for KPublicTransport <-> KOSMIndoorMap integration. */
class KOSMIndoorMapQuickPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
void registerTypes(const char *uri) override;
};
#endif // KOSMINDOORMAP_KPUBLICTRANSPORT_PLUGIN_H
/*
SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "locationqueryoverlayproxymodel.h"
#include <KPublicTransport/Location>
#include <KPublicTransport/LocationQueryModel>
#include <osm/element.h>
using namespace KOSMIndoorMap;
using namespace KPublicTransport;
LocationQueryOverlayProxyModel::LocationQueryOverlayProxyModel(QObject *parent)
: QAbstractListModel(parent)
{
}
LocationQueryOverlayProxyModel::~LocationQueryOverlayProxyModel() = default;
MapData* LocationQueryOverlayProxyModel::mapData() const
{
return m_data;
}
void LocationQueryOverlayProxyModel::setMapData(MapData* data)
{
// ### do not check for m_data != data, this does not actually change!
beginResetModel();
m_data = data;
initialize();
endResetModel();
emit mapDataChanged();
}
QAbstractItemModel* LocationQueryOverlayProxyModel::sourceModel() const
{
return m_sourceModel;
}
void LocationQueryOverlayProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
if (m_sourceModel == sourceModel) {
return;
}
beginResetModel();
m_sourceModel = sourceModel;
initialize();
// TODO watch for changes
endResetModel();
}
int LocationQueryOverlayProxyModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_nodes.size();
}
QVariant LocationQueryOverlayProxyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return {};
}
switch (role) {
case ElementRole:
return QVariant::fromValue(OSM::Element(&m_nodes[index.row()]));
case LevelRole:
return 0;
}
return {};
}
QHash<int, QByteArray> LocationQueryOverlayProxyModel::roleNames() const
{
auto n = QAbstractListModel::roleNames();
n.insert(ElementRole, "osmElement");
n.insert(LevelRole, "level");
return n;
}
void LocationQueryOverlayProxyModel::initialize()
{
static OSM::Id nextId = -1;
if (!m_data || !m_sourceModel) {
return;
}
const auto overlayTag = m_data->dataSet().makeTagKey("mx:overlay");
const auto capacityTag = m_data->dataSet().makeTagKey("capacity");
const auto availableTag = m_data->dataSet().makeTagKey("available");
m_nodes.clear();
const auto rows = m_sourceModel->rowCount();
m_nodes.reserve(rows);
for (int i = 0; i < rows; ++i) {
const auto idx = m_sourceModel->index(i, 0);
const auto loc = idx.data(LocationQueryModel::LocationRole).value<Location>();
OSM::Node node;
node.id = --nextId;
node.coordinate = OSM::Coordinate(loc.latitude(), loc.longitude());
OSM::setTagValue(node, overlayTag, "bike_rental");
OSM::setTagValue(node, capacityTag, QByteArray::number(loc.rentalVehicleStation().capacity()));
OSM::setTagValue(node, availableTag, QByteArray::number(loc.rentalVehicleStation().availableVehicles()));
m_nodes.push_back(std::move(node));
}
}
/*
SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KOSMINDOORMAP_LOCATIONQUERYOVERLAYPROXYMODEL_H
#define KOSMINDOORMAP_LOCATIONQUERYOVERLAYPROXYMODEL_H
#include <QAbstractItemModel>
#include <KOSMIndoorMap/MapData>
namespace OSM {
class Element;
class Node;
}
namespace KOSMIndoorMap {
/** Adapts a KPublicTransport::LocationQueryModel to be compatible with a KOSMIndoorMap::OverlaySource.
*/
class LocationQueryOverlayProxyModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(KOSMIndoorMap::MapData* mapData READ mapData WRITE setMapData NOTIFY mapDataChanged)
Q_PROPERTY(QAbstractItemModel* sourceModel READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged)
public:
explicit LocationQueryOverlayProxyModel(QObject *parent = nullptr);
~LocationQueryOverlayProxyModel();
MapData* mapData() const;
void setMapData(MapData *data);
QAbstractItemModel *sourceModel() const;
void setSourceModel(QAbstractItemModel *sourceModel);
enum Role {
ElementRole = Qt::UserRole,
LevelRole,
};
Q_ENUM(Role)
int rowCount(const QModelIndex &parent = {}) const override;
QVariant data(const QModelIndex & index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
Q_SIGNALS:
void mapDataChanged();
void sourceModelChanged();
private:
void initialize();
std::vector<OSM::Node> m_nodes;
MapData *m_data = nullptr;
QAbstractItemModel *m_sourceModel = nullptr;
};
}
#endif // KOSMINDOORMAP_LOCATIONQUERYOVERLAYPROXYMODEL_H
module org.kde.kosmindoormap.kpublictransport
plugin kosmindoormap_kpublictransport_integration_plugin
classname KOSMIndoorMapKPublicTransportIntegrationPlugin
......@@ -6,5 +6,6 @@
<file>css/diagnostic.mapcss</file>
<file>icons/bicycle_parking.svg</file>
<file>icons/bicycle_rental.svg</file>
</qresource>
</RCC>
......@@ -368,3 +368,14 @@ node|z18-[amenity=atm] { text: "🏧"; }
// hide information boards as their names clutter the vie
// showing an icon instead would be better, but we don't have one yet
node[information=board] { text: ""; }
// bicycle rental live data (WIP, this should be matched against regular bicycle_rental nodes)
node|z18-[mx:overlay=bike_rental] {
text: available;
text-color: #27ae60;
icon-image: "bicycle_rental";
}
node|z18-[mx:overlay=bike_rental][available=0] {
text-color: #da4453;
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="14"
height="14"
viewBox="0 0 14 14">
<style type="text/css" id="current-color-scheme"/>
<path
d="M 3.5,0 C 2.119288,0 1,1.1192881 1,2.5 1,3.8807119 2.119288,5 3.5,5 4.425342,5 5.223985,4.4972377 5.65625,3.75 L 7,3.75 l 1,-1 1,1 1,-1 1,1 0.5,0 L 13,2.5 11.5,1.25 5.65625,1.25 C 5.223985,0.5027623 4.425342,0 3.5,0 z m -1,2 C 2.776142,2 3,2.2238576 3,2.5 3,2.7761424 2.776142,3 2.5,3 2.223858,3 2,2.7761424 2,2.5 2,2.2238576 2.223858,2 2.5,2 z m 5.5,3.4375 0.03125,1 L 9,7 9,8 5.25,8 5,8 5,7 5.5,7 c 1,0 1,-1 0,-1 l -2,0 c -1,0 -1,1 0,1 L 4,7 4,8 3.4375,9.375 c -0.04165,-0.0023 -0.08284,0 -0.125,0 C 2.042004,9.375 1,10.417004 1,11.6875 1,12.957996 2.042004,14 3.3125,14 4.582996,14 5.625,12.957996 5.625,11.6875 5.625,11.447485 5.56957,11.218899 5.5,11 L 6,11 7,11 9.156,9 9.15625,9 9.4375,9.71875 C 8.797861,10.135655 8.375,10.877559 8.375,11.6875 8.375,12.957996 9.417004,14 10.6875,14 c 1.270496,0 2.34375,-1.042004 2.34375,-2.3125 0,-1.270496 -1.073254,-2.3125 -2.34375,-2.3125 -0.04216,0 -0.08335,-0.0023 -0.125,0 L 10,8 10,6.625 z M 4.84375,9 7.956,9 6.65,10.25 l -1.55625,0 C 4.939889,10.062277 4.766292,9.851578 4.5625,9.71875 z M 3.3125,10.5 C 3.975001,10.5 4.5,11.024999 4.5,11.6875 4.5,12.350001 3.975001,12.875 3.3125,12.875 2.649999,12.875 2.125,12.350001 2.125,11.6875 2.125,11.024999 2.649999,10.5 3.3125,10.5 z m 7.375,0 c 0.662501,0 1.1875,0.524999 1.1875,1.1875 0,0.662501 -0.524999,1.1875 -1.1875,1.1875 -0.662501,0 -1.15625,-0.524999 -1.15625,-1.1875 0,-0.662501 0.493749,-1.1875 1.15625,-1.1875 z"
id="rental-bicycle" class="ColorScheme-Text" style="fill:currentColor;"/>
</svg>
SPDX-License-Identifier: CC0-1.0
SPDX-FileCopyrightText: https://github.com/gravitystorm/openstreetmap-carto
......@@ -22,6 +22,7 @@ import Qt.labs.platform 1.0 as QPlatform
import org.kde.kirigami 2.0 as Kirigami
import org.kde.kpublictransport 1.0 as PublicTransport
import org.kde.kosmindoormap 1.0
import org.kde.kosmindoormap.kpublictransport 1.0
Kirigami.ApplicationWindow {
title: "OSM Indoor Map QML Test"
......@@ -212,7 +213,16 @@ Kirigami.ApplicationWindow {
}
}
map.overlaySources: [ gateModel, platformModel ]
LocationQueryOverlayProxyModel {
id: locationModel
sourceModel: PublicTransport.LocationQueryModel {
id: locationQuery
manager: ptMgr
}
mapData: page.map.mapData
}
map.overlaySources: [ gateModel, platformModel, locationModel ]
header: RowLayout {
QQC2.Label { text: "Floor Level:" }
......@@ -261,6 +271,10 @@ Kirigami.ApplicationWindow {
var lat = c[1];
var lon = c[2];
page.map.mapLoader.loadForCoordinate(lat, lon);
locationQuery.request.latitude = lat;
locationQuery.request.longitude = lon;
locationQuery.request.maximumDistance = 1000; // TODO
locationQuery.request.types = PublicTransport.Location.RentedVehicleStation;
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment