KPublicTransport

vehicle.cpp
1/*
2 SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "vehicle.h"
8#include "json_p.h"
9#include "datatypes_p.h"
10#include "featureutil_p.h"
11#include "mergeutil_p.h"
12
13#include <QDebug>
14#include <QMetaEnum>
15#include <QVariant>
16
17#include <limits>
18
19using namespace Qt::Literals::StringLiterals;
20using namespace KPublicTransport;
21
22namespace KPublicTransport {
23
24class VehicleSectionPrivate : public QSharedData
25{
26public:
27 QString name;
28 float platformPositionBegin = -1.0;
29 float platformPositionEnd = -1.0;
30 VehicleSection::Type type = VehicleSection::UnknownType;
31 VehicleSection::Classes classes = VehicleSection::UnknownClass;
32 int deckCount = 1;
33 VehicleSection::Sides connectedSides = VehicleSection::Front | VehicleSection::Back;
34 QString platformSectionName;
35 std::vector<Feature> sectionFeatures;
36 Disruption::Effect disruptionEffect = Disruption::NormalService;
38};
39
40class VehiclePrivate : public QSharedData
41{
42public:
43 QString name;
44 std::vector<VehicleSection> sections;
45 Vehicle::Direction direction = Vehicle::UnknownDirection;
46 std::vector<Feature> features;
47};
48
49}
50
51KPUBLICTRANSPORT_MAKE_GADGET(VehicleSection)
52KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, QString, name, setName)
53KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, float, platformPositionBegin, setPlatformPositionBegin)
54KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, float, platformPositionEnd, setPlatformPositionEnd)
55KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, VehicleSection::Type, type, setType)
56KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, VehicleSection::Classes, classes, setClasses)
57KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, int, deckCount, setDeckCount)
58KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, VehicleSection::Sides, connectedSides, setConnectedSides)
59KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, QString, platformSectionName, setPlatformSectionName)
60KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, KPublicTransport::Disruption::Effect, disruptionEffect, setDisruptionEffect)
61KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, KPublicTransport::Load::Category, load, setLoad)
62
64{
65 struct {
66 KPublicTransport::Feature::Type type;
67 Feature legacyType;
68 } constexpr map[] = {
69 { KPublicTransport::Feature::AirConditioning, AirConditioning },
70 { KPublicTransport::Feature::Restaurant, Restaurant },
71 { KPublicTransport::Feature::ToddlerArea, ToddlerArea },
72 { KPublicTransport::Feature::WheelchairAccessible, WheelchairAccessible },
73 { KPublicTransport::Feature::SilentArea, SilentArea },
74 { KPublicTransport::Feature::BikeStorage, BikeStorage },
75 };
76
78 for (const auto &f : d->sectionFeatures) {
79 if (f.availability() == KPublicTransport::Feature::Unavailable) {
80 continue;
81 }
82 const auto it = std::find_if(std::begin(map), std::end(map), [&f](auto m) { return m.type == f.type(); });
83 if (it == std::end(map)) {
84 continue;
85 }
86 features |= (*it).legacyType;
87 }
88
89 return features;
90}
91
92[[nodiscard]] static constexpr KPublicTransport::Feature::Type fromLegacyFeature(int f)
93{
94 constexpr KPublicTransport::Feature::Type map[] = {
95 KPublicTransport::Feature::NoFeature,
96 KPublicTransport::Feature::AirConditioning,
97 KPublicTransport::Feature::Restaurant,
98 KPublicTransport::Feature::ToddlerArea,
99 KPublicTransport::Feature::WheelchairAccessible,
100 KPublicTransport::Feature::SilentArea,
101 KPublicTransport::Feature::BikeStorage,
102 };
103 return map[f];
104}
105
106void VehicleSection::setFeatures(Features features)
107{
108 d.detach();
109 if (features) {
110 std::vector<KPublicTransport::Feature> fs;
112 for (int i = 0; i < me.keyCount(); ++i) {
113 if (const auto v = static_cast<VehicleSection::Feature>(me.value(i)); features & v) {
114 fs.emplace_back(fromLegacyFeature(i), KPublicTransport::Feature::Available);
115 }
116 }
117 FeatureUtil::set(d->sectionFeatures, std::move(fs));
118 } else {
119 d->sectionFeatures.clear();
120 }
121}
122
123const std::vector<KPublicTransport::Feature>& VehicleSection::sectionFeatures() const
124{
125 return d->sectionFeatures;
126}
127
128std::vector<KPublicTransport::Feature>&& VehicleSection::takeSectionFeatures()
129{
130 return std::move(d->sectionFeatures);
131}
132
133void VehicleSection::setSectionFeatures(std::vector<KPublicTransport::Feature> &&features)
134{
135 d.detach();
136 FeatureUtil::set(d->sectionFeatures, std::move(features));
137}
138
139KPublicTransport::Feature VehicleSection::feature(KPublicTransport::Feature::Type type) const
140{
141 return FeatureUtil::findByType(d->sectionFeatures, type);
142}
143
144QString VehicleSection::vehicleTypeIconName(VehicleSection::Type type)
145{
146 switch (type) {
147 case VehicleSection::UnknownType:
148 case VehicleSection::Engine:
149 case VehicleSection::PowerCar:
150 break;
151 case VehicleSection::PassengerCar:
152 case VehicleSection::ControlCar:
153 return u"qrc:///org.kde.kpublictransport/assets/images/seat.svg"_s;
154 case VehicleSection::SleepingCar:
155 return u"qrc:///org.kde.kpublictransport/assets/images/sleepingcar.svg"_s;
156 case VehicleSection::CouchetteCar:
157 return u"qrc:///org.kde.kpublictransport/assets/images/couchettecar.svg"_s;
158 case VehicleSection::RestaurantCar:
159 return u"qrc:///org.kde.kpublictransport/assets/images/restaurant.svg"_s;
160 case VehicleSection::CarTransportCar:
161 return u"qrc:///org.kde.kpublictransport/assets/images/car.svg"_s;
162 }
163 return {};
164}
165
167{
168 return vehicleTypeIconName(type());
169}
170
171VehicleSection VehicleSection::merge(const VehicleSection &lhs, const VehicleSection &rhs)
172{
173 if (lhs.name() != rhs.name()) { // safety check, as we don't properly check for equalness before merging yet
174 return lhs;
175 }
176
177 auto res = lhs;
178 res.setPlatformPositionBegin(lhs.platformPositionBegin() < 0.0 ? rhs.platformPositionBegin() : lhs.platformPositionBegin());
179 res.setPlatformPositionEnd(lhs.platformPositionEnd() < 0.0 ? rhs.platformPositionEnd() : lhs.platformPositionEnd());
180 res.setType(std::max(lhs.type(), rhs.type()));
181 if (res.type() == VehicleSection::PassengerCar && lhs.type() != VehicleSection::UnknownType && rhs.type() != VehicleSection::UnknownType) {
182 res.setType(std::min(lhs.type(), rhs.type()));
183 }
184 res.setClasses(lhs.classes() | rhs.classes());
185 res.setFeatures(lhs.features() | rhs.features());
186 res.setDeckCount(std::max(lhs.deckCount(), rhs.deckCount()));
187 res.setConnectedSides(lhs.connectedSides() & rhs.connectedSides());
188 res.setPlatformSectionName(MergeUtil::mergeString(lhs.platformSectionName(), rhs.platformSectionName()));
189 res.setSectionFeatures(FeatureUtil::merge(lhs.sectionFeatures(), rhs.sectionFeatures()));
190 return res;
191}
192
193QJsonObject VehicleSection::toJson(const VehicleSection &section)
194{
195 auto obj = Json::toJson(section);
196 if (!section.d->sectionFeatures.empty()) {
197 obj.insert("features"_L1, KPublicTransport::Feature::toJson(section.d->sectionFeatures));
198 }
199 if (section.disruptionEffect() == Disruption::NormalService) {
200 obj.remove("disruptionEffect"_L1);
201 }
202 if (section.load() == Load::Unknown) {
203 obj.remove("load"_L1);
204 }
205 return obj;
206}
207
208QJsonArray VehicleSection::toJson(const std::vector<VehicleSection> &sections)
209{
210 return Json::toJson(sections);
211}
212
213VehicleSection VehicleSection::fromJson(const QJsonObject &obj)
214{
215 auto v = Json::fromJson<VehicleSection>(obj);
216 const auto fVal = obj.value("features"_L1);
217 if (fVal.isArray()) {
218 v.setSectionFeatures(KPublicTransport::Feature::fromJson(fVal.toArray()));
219 } else if (fVal.isString()) {
220 // backward compat for existing data
221 v.setFeatures(Json::flagsFromJson<Features>(fVal));
222 }
223 return v;
224}
225
226std::vector<VehicleSection> VehicleSection::fromJson(const QJsonArray &array)
227{
228 return Json::fromJson<VehicleSection>(array);
229}
230
231QVariantList VehicleSection::featureList() const
232{
233 QVariantList l;
235 for (int i = 0; i < me.keyCount(); ++i) {
236 if (features() & static_cast<VehicleSection::Feature>(1 << i)) {
237 l.push_back(static_cast<VehicleSection::Feature>(1 << i));
238 }
239 }
240 return l;
241}
242
243bool VehicleSection::hasPlatformPosition() const
244{
245 return d->platformPositionBegin >= 0.0 && d->platformPositionEnd >= 0.0;
246}
247
248KPUBLICTRANSPORT_MAKE_GADGET(Vehicle)
249KPUBLICTRANSPORT_MAKE_PROPERTY(Vehicle, QString, name, setName)
250KPUBLICTRANSPORT_MAKE_PROPERTY(Vehicle, Vehicle::Direction, direction, setDirection)
251
252bool Vehicle::isEmpty() const
253{
254 return d->name.isEmpty() && d->sections.empty() && d->direction == Vehicle::UnknownDirection && d->features.empty();
255}
256
257const std::vector<VehicleSection>& Vehicle::sections() const
258{
259 return d->sections;
260}
261
262std::vector<VehicleSection>&& Vehicle::takeSections()
263{
264 d.detach();
265 return std::move(d->sections);
266}
267
268void Vehicle::setSections(std::vector<VehicleSection> &&sections)
269{
270 d.detach();
271 d->sections = std::move(sections);
272}
273
274void Vehicle::setSections(const std::vector<VehicleSection> &sections)
275{
276 d.detach();
277 d->sections = sections;
278}
279
280QVariantList Vehicle::sectionsVariant() const
281{
282 QVariantList l;
283 l.reserve(d->sections.size());
284 std::transform(d->sections.begin(), d->sections.end(), std::back_inserter(l), [](const auto &sec) { return QVariant::fromValue(sec); });
285 return l;
286}
287
289{
290 float p = std::numeric_limits<float>::max();
291 for (const auto &section : sections()) {
292 p = std::min(p, section.platformPositionBegin());
293 }
294 return p;
295}
296
298{
299 float p = -1.0f;
300 for (const auto &section : sections()) {
301 p = std::max(p, section.platformPositionEnd());
302 }
303 return p;
304}
305
306float Vehicle::platformPositionForSection(const QString &sectionName) const
307{
308 for (const auto &section : sections()) {
309 if (section.name() == sectionName) {
310 return (section.platformPositionBegin() + section.platformPositionEnd()) / 2.0f;
311 }
312 }
313 return -1.0f;
314}
315
316Vehicle Vehicle::merge(const Vehicle &lhs, const Vehicle &rhs)
317{
318 Vehicle res;
319 res.setDirection(lhs.direction() == Vehicle::UnknownDirection ? rhs.direction() : lhs.direction());
320 res.setName(MergeUtil::mergeString(lhs.name(), rhs.name()));
321
322 if (lhs.sections().size() == rhs.sections().size()) {
323 std::vector<VehicleSection> secs;
324 secs.reserve(lhs.sections().size());
325 for (std::size_t i = 0; i < lhs.sections().size(); ++i) {
326 const auto &lhsSec = lhs.sections()[i];
327 const auto &rhsSec = rhs.sections()[i];
328 secs.push_back(VehicleSection::merge(lhsSec, rhsSec));
329 }
330 res.setSections(std::move(secs));
331 } else {
332 res.setSections(lhs.sections().size() < rhs.sections().size() ? rhs.sections() : lhs.sections());
333 }
334
335 res.setFeatures(FeatureUtil::merge(lhs.features(), rhs.features()));
336
337 return res;
338}
339
341{
342 auto obj = Json::toJson(vehicle);
343 if (!vehicle.sections().empty()) {
344 obj.insert("sections"_L1, VehicleSection::toJson(vehicle.sections()));
345 }
346 if (!vehicle.features().empty()) {
347 obj.insert("features"_L1, Feature::toJson(vehicle.features()));
348 }
349 return obj;
350}
351
352QJsonArray Vehicle::toJson(const std::vector<Vehicle> &vehicles)
353{
354 return Json::toJson(vehicles);
355}
356
358{
359 auto v = Json::fromJson<Vehicle>(obj);
360 v.setSections(VehicleSection::fromJson(obj.value("sections"_L1).toArray()));
361 v.setFeatures(Feature::fromJson(obj.value("features"_L1).toArray()));
362 return v;
363}
364
365std::vector<Vehicle> Vehicle::fromJson(const QJsonArray &array)
366{
367 return Json::fromJson<Vehicle>(array);
368}
369
371{
372 return std::all_of(d->sections.begin(), d->sections.end(), [](const auto &p) { return p.hasPlatformPosition(); });
373}
374
376{
377 return std::none_of(d->sections.begin(), d->sections.end(), [](const auto &p) { return p.platformSectionName().isEmpty(); });
378}
379
380const std::vector<KPublicTransport::Feature>& Vehicle::features() const
381{
382 return d->features;
383}
384
385[[nodiscard]] std::vector<KPublicTransport::Feature>&& Vehicle::takeFeatures()
386{
387 return std::move(d->features);
388}
389
390void Vehicle::setFeatures(std::vector<KPublicTransport::Feature> &&features)
391{
392 d.detach();
393 d->features = std::move(features);
394}
395
396std::vector<KPublicTransport::Feature> Vehicle::combinedFeatures() const
397{
398 std::vector<KPublicTransport::Feature> features(d->features);
399 for (const auto &section : d->sections) {
400 for (const auto &feature : section.sectionFeatures()) {
401 FeatureUtil::aggregate(features, feature);
402 }
403 }
404 return features;
405}
406
407#include "moc_vehicle.cpp"
An amenity, facility or other relevant property of a vehicle (train, bus, etc), vehicle part (e....
Definition feature.h:20
static Feature fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition feature.cpp:100
static QJsonObject toJson(const Feature &feature)
Serializes one object to JSON.
Definition feature.cpp:86
Information about a part of a vehicle.
Definition vehicle.h:25
QString name
Human readable identifier of this section, typically the coach number.
Definition vehicle.h:31
QVariantList featureList
Feature flag as a variant list, for consumption in QML.
Definition vehicle.h:97
KPublicTransport::Load::Category load
Occupancy level for this coach.
Definition vehicle.h:137
Type type
Type of this vehicle section.
Definition vehicle.h:56
std::vector< KPublicTransport::Feature > sectionFeatures
Features of this section, for consumption by QML.
Definition vehicle.h:100
QString iconName
A suitable icon representing the coach.
Definition vehicle.h:157
Features features
Features available in this vehicle section.
Definition vehicle.h:90
QString platformSectionName
Name of the platform section(s) this coach is position in.
Definition vehicle.h:142
KPublicTransport::Disruption::Effect disruptionEffect
Distruption affecting this coach.
Definition vehicle.h:134
float platformPositionBegin
Relative position [0-1] of the begin of this vehicle section on the platform.
Definition vehicle.h:36
Classes classes
Classes available in this vehicle section.
Definition vehicle.h:70
Sides connectedSides
Sides on which this vehicle section is connected to neighboring sections in a way that passengers can...
Definition vehicle.h:129
int deckCount
Number of decks in this vehicle section.
Definition vehicle.h:112
float platformPositionEnd
Relative position [0-1] of the end of this vehicle section on the platform.
Definition vehicle.h:40
Information about the vehicle used on a journey.
Definition vehicle.h:186
static QJsonObject toJson(const Vehicle &vehicle)
Serializes one vehicle object to JSON.
Definition vehicle.cpp:340
QVariantList sections
Journey sections for consumption by QML.
Definition vehicle.h:202
void setSections(std::vector< VehicleSection > &&sections)
Sets the vehicle sections.
Definition vehicle.cpp:268
float platformPositionBegin
Relative position [0-1] of the begin of this vehicle on the platform.
Definition vehicle.h:207
bool hasPlatformPositions() const
Checks whether all vehicle sections have platform positions set.
Definition vehicle.cpp:370
static Vehicle fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition vehicle.cpp:357
Direction direction
Direction of travel of this vehicle.
Definition vehicle.h:199
float platformPositionEnd
Relative position [0-1] of the end of this vehicle on the platform.
Definition vehicle.h:211
bool hasPlatformSectionNames() const
Check whether all vehicle sections have platform section names set.
Definition vehicle.cpp:375
std::vector< KPublicTransport::Feature > combinedFeatures
Features of the entire vehicle including a union of all features of the individual sections.
Definition vehicle.h:217
std::vector< KPublicTransport::Feature > features
Features of this vehicle as a whole, not including the features of individual sections.
Definition vehicle.h:214
std::vector< VehicleSection > && takeSections()
Moves the vehicle sections out of this object.
Definition vehicle.cpp:262
Q_INVOKABLE float platformPositionForSection(const QString &sectionName) const
Returns the center position of the vehicle section named sectionName in relative platform coordinates...
Definition vehicle.cpp:306
static Vehicle merge(const Vehicle &lhs, const Vehicle &rhs)
Merge two Vehicle instances.
Definition vehicle.cpp:316
QString name
Human readable identifier of this vehicle, typically a train number.
Definition vehicle.h:189
Effect
Disruption effects, numerical sorted so that higher values imply more severe disruptions.
Definition disruption.h:25
Category
Vehicle load categories.
Definition load.h:20
@ Unknown
no load information are available
Definition load.h:21
Query operations and data types for accessing realtime public transport information from online servi...
iterator insert(QLatin1StringView key, const QJsonValue &value)
QJsonValue value(QLatin1StringView key) const const
QJsonArray toArray() const const
QMetaEnum fromType()
bool isEmpty() const const
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:59:21 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.