Commit 02d81104 authored by Volker Krause's avatar Volker Krause
Browse files

Parse floor level change information from EFA transfer navigation paths

parent cb78499c
......@@ -91,6 +91,8 @@
},
{
"description": "Aufzug abw�rts",
"floorLevelChange": -2,
"maneuver": "Elevator",
"path": {
"coordinates": [
[
......@@ -151,6 +153,8 @@
},
{
"description": "Rolltreppe abw�rts",
"floorLevelChange": -2,
"maneuver": "Escalator",
"path": {
"coordinates": [
[
......@@ -239,6 +243,8 @@
},
{
"description": "Rolltreppe aufw�rts",
"floorLevelChange": 4,
"maneuver": "Escalator",
"path": {
"coordinates": [
[
......@@ -291,6 +297,8 @@
},
{
"description": "Rolltreppe aufw�rts",
"floorLevelChange": 1,
"maneuver": "Escalator",
"path": {
"coordinates": [
[
......
......@@ -368,6 +368,7 @@ std::vector<JourneySection> EfaXmlParser::parseTripPartialRoute(ScopedXmlStreamR
}
if (!pathDesc.empty()) {
resolvePathDescription(pathDesc);
if (!transferPoly.empty() && section.mode() == JourneySection::PublicTransport) {
// path description is actually for a subsequent transfer section
const auto path = assemblePath(pathDesc, transferPoly);
......@@ -474,9 +475,20 @@ std::vector<EfaXmlParser::PathDescription> EfaXmlParser::parsePathDescriptionLis
desc.description = elemReader.readElementText();
} else if (elemReader.name() == QLatin1String("traveltime")) {
desc.travelTime = elemReader.readElementText().toInt();
} else if (elemReader.name() == QLatin1String("niveau")) {
// seems to match OSM floor level, but is always "0" for elevators/escalators
desc.niveau = elemReader.readElementText().toInt();
} else if (elemReader.name() == QLatin1String("genAttrList")) {
const auto attrs = parseGenericAttributeList(elemReader.subReader());
const auto indoorType = attrs.value(QLatin1String("INDOOR_TYPE"));
if (indoorType == QLatin1String("LIFT")) {
desc.maneuver = PathSection::Elevator;
} else if (indoorType == QLatin1String("ESCALATOR")) {
desc.maneuver = PathSection::Escalator;
}
}
// NOTE: skyDirection seems flipped by 180°, ie. pointing to the start point, should we ever need that
// turnDirection, turningManoeuvre, from/toPathLink??, niveau, genAttrList
// turnDirection, turningManoeuvre, from/toPathLink??
}
descs.push_back(std::move(desc));
}
......@@ -484,6 +496,22 @@ std::vector<EfaXmlParser::PathDescription> EfaXmlParser::parsePathDescriptionLis
return descs;
}
void EfaXmlParser::resolvePathDescription(std::vector<PathDescription> &descs) const
{
if (descs.size() < 3) {
return;
}
for (auto it = std::next(descs.begin()); it != std::prev(descs.end()); ++it) {
if ((*it).maneuver != PathSection::Elevator && (*it).maneuver != PathSection::Escalator) {
continue;
}
const auto niveauBefore = (*std::prev(it)).niveau;
const auto niveauAfter = (*std::next(it)).niveau;
(*it).niveauDelta = niveauAfter - niveauBefore;
}
}
Path EfaXmlParser::assemblePath(const std::vector<PathDescription> &descs, const QPolygonF &poly) const
{
Path path;
......@@ -500,9 +528,31 @@ Path EfaXmlParser::assemblePath(const std::vector<PathDescription> &descs, const
std::copy(poly.begin() + desc.fromIndex, poly.begin() + desc.toIndex + 1, std::back_inserter(subPoly));
section.setPath(subPoly);
section.setDescription(desc.description);
section.setManeuver(desc.maneuver);
section.setFloorLevelChange(desc.niveauDelta);
sections.push_back(std::move(section));
}
path.setSections(std::move(sections));
return path;
}
QHash<QString, QString> EfaXmlParser::parseGenericAttributeList(ScopedXmlStreamReader &&reader) const
{
QHash<QString, QString> attrs;
while (reader.readNextSibling()) {
if (reader.name() == QLatin1String("genAttrElem")) {
auto attrReader = reader.subReader();
QString name, value;
while (attrReader.readNextSibling()) {
if (attrReader.name() == QLatin1String("name")) {
name = attrReader.readElementText();
} else if (attrReader.name() == QLatin1String("value")) {
value = attrReader.readElementText();
}
}
attrs.insert(name, value);
}
}
return attrs;
}
......@@ -9,6 +9,8 @@
#include "efaparser.h"
#include <KPublicTransport/Path>
#include <QPointF>
class QPolygonF;
......@@ -50,11 +52,15 @@ private:
int toIndex = -1;
QString description;
int travelTime = 0;
int niveau = 0;
int niveauDelta = 0;
PathSection::Maneuver maneuver = PathSection::Move;
};
std::vector<PathDescription> parsePathDescriptionList(ScopedXmlStreamReader &&reader) const;
void resolvePathDescription(std::vector<PathDescription> &descs) const;
Path assemblePath(const std::vector<PathDescription> &descs, const QPolygonF &poly) const;
QHash<QString, QString> parseGenericAttributeList(ScopedXmlStreamReader &&reader) const;
mutable QHash<QString, Location> m_locations;
};
......
......@@ -19,12 +19,16 @@ class PathSectionPrivate : public QSharedData {
public:
QPolygonF path;
QString description;
int floorLevelChange = 0;
PathSection::Maneuver maneuver = PathSection::Move;
};
}
KPUBLICTRANSPORT_MAKE_GADGET(PathSection)
KPUBLICTRANSPORT_MAKE_PROPERTY(PathSection, QPolygonF, path, setPath)
KPUBLICTRANSPORT_MAKE_PROPERTY(PathSection, QString, description, setDescription)
KPUBLICTRANSPORT_MAKE_PROPERTY(PathSection, int, floorLevelChange, setFloorLevelChange)
KPUBLICTRANSPORT_MAKE_PROPERTY(PathSection, PathSection::Maneuver, maneuver, setManeuver)
int PathSection::distance() const
{
......@@ -55,7 +59,7 @@ QPointF PathSection::startPoint() const
return d->path.empty() ? QPointF() : d->path.constFirst();
}
QPointF KPublicTransport::PathSection::endPoint() const
QPointF PathSection::endPoint() const
{
return d->path.empty() ? QPointF() : d->path.constLast();
}
......@@ -66,6 +70,12 @@ QJsonObject PathSection::toJson(const PathSection &section)
if (!section.path().empty()) {
obj.insert(QLatin1String("path"), GeoJson::writeLineString(section.path()));
}
if (section.maneuver() == PathSection::Move) {
obj.remove(QLatin1String("maneuver"));
}
if (section.floorLevelChange() == 0) {
obj.remove(QLatin1String("floorLevelChange"));
}
return obj;
}
......
......@@ -36,6 +36,22 @@ class KPUBLICTRANSPORT_EXPORT PathSection
/** The overall direction of this section in degree. */
Q_PROPERTY(int direction READ direction STORED false)
/** Floor level change during this path section.
* Negative values indicate going down, positive values indicate going up
*/
KPUBLICTRANSPORT_PROPERTY(int, floorLevelChange, setFloorLevelChange)
public:
/** Maneuver associated with a path section. */
enum Maneuver {
Move, ///< Move/drive with the default mode of transport for this path
Elevator, ///< Take an elevator
Escalator, ///< Take an escalator
};
Q_ENUM(Maneuver)
/** Movement maneuver for this path section. */
KPUBLICTRANSPORT_PROPERTY(Maneuver, maneuver, setManeuver)
public:
/** Length of this path section in meters. */
int distance() const;
......
Supports Markdown
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