KPublicTransport

coveragearea.cpp
1/*
2 SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "coveragearea.h"
8#include "datatypes_p.h"
9#include "json_p.h"
10#include "location.h"
11#include "logging.h"
12#include "geo/geojson_p.h"
13
14#include <QFile>
15#include <QJsonDocument>
16#include <QJsonObject>
17#include <QPolygonF>
18
19using namespace KPublicTransport;
20
21namespace KPublicTransport {
22class CoverageAreaPrivate : public QSharedData {
23public:
24 void loadGeometry();
25 void recomputeBoundingBox();
26
27 CoverageArea::Type type = CoverageArea::Any;
28 QStringList regions;
29 QStringList uicCompanyCodes;
30 QStringList vdvOrganizationIds;
31 QString areaFile;
32 std::vector<QPolygonF> areas;
33 QRectF boundingBox;
34};
35}
36
37void CoverageAreaPrivate::loadGeometry()
38{
39 if (areaFile.isEmpty() || !areas.empty()) {
40 return;
41 }
42
43 QFile f(QLatin1String(":/org.kde.kpublictransport/networks/geometry/") + areaFile);
44 if (!f.open(QFile::ReadOnly)) {
45 qCWarning(Log) << "reading coverage area file failed:" << f.fileName() << f.errorString();
46 return;
47 }
48
49 const auto doc = QJsonDocument::fromJson(f.readAll());
50 areas = GeoJson::readOuterPolygons(doc.object());
51 recomputeBoundingBox();
52}
53
54void CoverageAreaPrivate::recomputeBoundingBox()
55{
56 for (const auto &area : areas) {
57 boundingBox |= area.boundingRect();
58 }
59}
60
61KPUBLICTRANSPORT_MAKE_GADGET(CoverageArea)
62KPUBLICTRANSPORT_MAKE_PROPERTY(CoverageArea, CoverageArea::Type, type, setType)
63KPUBLICTRANSPORT_MAKE_PROPERTY(CoverageArea, QStringList, regions, setRegions)
64KPUBLICTRANSPORT_MAKE_PROPERTY(CoverageArea, QStringList, uicCompanyCodes, setUicCompanyCodes)
65KPUBLICTRANSPORT_MAKE_PROPERTY(CoverageArea, QStringList, vdvOrganizationIds, setVdvOrganizationIds)
66
67bool CoverageArea::isEmpty() const
68{
69 return d->regions.isEmpty() && d->areas.empty();
70}
71
73{
74 if (d->regions.size() == 1 && d->regions.at(0) == QLatin1String("UN")) {
75 return true;
76 }
77
78 return d->boundingBox.topLeft() == QPointF(-180.0, -90.0) && d->boundingBox.bottomRight() == QPointF(180.0, 90.0);
79}
80
81static QStringView countryCode(QStringView isoCode)
82{
83 return isoCode.size() < 2 ? QStringView() : isoCode.left(2);
84}
85
87{
88 if (loc.hasCoordinate()) {
89 d->loadGeometry();
90 if (!d->areas.empty()) {
91 if (d->boundingBox.contains({loc.longitude(), loc.latitude()})) {
92 return std::any_of(d->areas.begin(), d->areas.end(), [&loc](const auto &area) {
93 return area.containsPoint({loc.longitude(), loc.latitude()}, Qt::WindingFill);
94 });
95 }
96 return false;
97 }
98 }
99
100 // TODO we could do a more precise check for ISO 3166-2 subdivision codes when available
101
102 if (loc.country().size() == 2 && !d->regions.empty()) {
103 if (d->regions.size() == 1 && d->regions.at(0) == QLatin1String("UN")) { // global coverage
104 return true;
105 }
106 return std::binary_search(d->regions.begin(), d->regions.end(), loc.country(), [](const auto &lhs, const auto &rhs) {
107 return countryCode(lhs) < countryCode(rhs);
108 });
109 }
110
111 // if we have nothing to check against, assume the backend can help (otherwise none would trigger)
112 return true;
113}
114
116{
117 return std::binary_search(d->regions.begin(), d->regions.end(), country);
118}
119
121{
122 CoverageArea ca;
123 ca.setRegions(Json::toStringList(obj.value(QLatin1String("region"))));
124 ca.setUicCompanyCodes(Json::toStringList(obj.value(QLatin1String("uicCompanyCodes"))));
125 std::sort(ca.d->regions.begin(), ca.d->regions.end());
126
127 ca.d->areaFile = obj.value(QLatin1String("areaFile")).toString();
128 if (ca.d->areaFile.isEmpty()) {
129 ca.d->areas = GeoJson::readOuterPolygons(obj.value(QLatin1String("area")).toObject());
130 ca.d->recomputeBoundingBox();
131 }
132 return ca;
133}
134
135#include "moc_coveragearea.cpp"
Describes the area a specific KPublicTransport::Backend can provide information for.
bool isGlobal() const
Returns true if this area covers the entire world.
bool hasNationWideCoverage(const QString &country) const
Checks whether this includes the entire country country.
QStringList regions
ISO 3166-1/2 codes of covered regions.
Type
Coverage quality as defined by the Transport API Repository format.
bool isEmpty() const
Checks whether this coverage area is empty.
bool coversLocation(const Location &loc) const
Checks whether loc is covered by this area.
static CoverageArea fromJson(const QJsonObject &obj)
Read a single coverage area information from a JSON object in Transport API Repository format.
Query operations and data types for accessing realtime public transport information from online servi...
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonValue value(QLatin1StringView key) const const
QString toString() const const
iterator begin()
iterator end()
bool isEmpty() const const
bool isEmpty() const const
qsizetype size() const const
WindingFill
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:06 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.