KPublicTransport

journey.cpp
1/*
2 SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "journey.h"
8#include "journeyutil_p.h"
9#include "json_p.h"
10#include "datatypes_p.h"
11#include "loadutil_p.h"
12#include "logging.h"
13#include "mergeutil_p.h"
14#include "notesutil_p.h"
15#include "platformutils_p.h"
16#include "rentalvehicle.h"
17#include "rentalvehicleutil_p.h"
18#include "stopover.h"
19
20#include <QDebug>
21#include <QVariant>
22
23using namespace Qt::Literals::StringLiterals;
24using namespace KPublicTransport;
25
26namespace KPublicTransport {
27
28class JourneySectionPrivate : public QSharedData
29{
30public:
31 JourneySection::Mode mode = JourneySection::Invalid;
32 QDateTime scheduledDepartureTime;
33 QDateTime expectedDepartureTime;
34 QDateTime scheduledArrivalTime;
35 QDateTime expectedArrivalTime;
36 Location from;
37 Location to;
38 Route route;
39 QString scheduledDeparturePlatform;
40 QString expectedDeparturePlatform;
41 QString scheduledArrivalPlatform;
42 QString expectedArrivalPlatform;
43 int distance = 0;
44 Disruption::Effect disruptionEffect = Disruption::NormalService;
45 QStringList notes;
46 std::vector<Stopover> intermediateStops;
47 int co2Emission = -1;
48 std::vector<LoadInfo> loadInformation;
49 RentalVehicle rentalVehicle;
50 Path path;
51 Vehicle departureVehicleLayout;
52 Platform departurePlatformLayout;
53 Vehicle arrivalVehicleLayout;
54 Platform arrivalPlatformLayout;
55 IndividualTransport individualTransport;
56};
57
58class JourneyPrivate : public QSharedData
59{
60public:
61 std::vector<JourneySection> sections;
62};
63
64}
65
66KPUBLICTRANSPORT_MAKE_GADGET(JourneySection)
67KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, JourneySection::Mode, mode, setMode)
68KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, scheduledDepartureTime, setScheduledDepartureTime)
69KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, expectedDepartureTime, setExpectedDepartureTime)
70KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, scheduledArrivalTime, setScheduledArrivalTime)
71KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, expectedArrivalTime, setExpectedArrivalTime)
72KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Location, from, setFrom)
73KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Location, to, setTo)
74KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Route, route, setRoute)
75KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Disruption::Effect, disruptionEffect, setDisruptionEffect)
76KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QStringList, notes, setNotes)
77KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, RentalVehicle, rentalVehicle, setRentalVehicle)
78KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Path, path, setPath)
79KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Vehicle, departureVehicleLayout, setDepartureVehicleLayout)
80KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Platform, departurePlatformLayout, setDeparturePlatformLayout)
81KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Vehicle, arrivalVehicleLayout, setArrivalVehicleLayout)
82KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Platform, arrivalPlatformLayout, setArrivalPlatformLayout)
83KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, KPublicTransport::IndividualTransport, individualTransport, setIndividualTransport)
84
86{
87 return d->expectedDepartureTime.isValid();
88}
89
91{
93 return d->scheduledDepartureTime.secsTo(d->expectedDepartureTime) / 60;
94 }
95 return 0;
96}
97
99{
100 return d->expectedArrivalTime.isValid();
101}
102
104{
106 return d->scheduledArrivalTime.secsTo(d->expectedArrivalTime) / 60;
107 }
108 return 0;
109}
110
111int JourneySection::duration() const
112{
113 return d->scheduledDepartureTime.secsTo(d->scheduledArrivalTime);
114}
115
116int JourneySection::distance() const
117{
118 if (d->mode == JourneySection::Waiting) {
119 return 0;
120 }
121
122 double dist = 0;
123 if (d->from.hasCoordinate() && d->to.hasCoordinate()) {
124 auto startLat = d->from.latitude();
125 auto startLon = d->from.longitude();
126
127 for (const auto &stop : d->intermediateStops) {
128 if (!stop.stopPoint().hasCoordinate()) {
129 continue;
130 }
131 dist += Location::distance(startLat, startLon, stop.stopPoint().latitude(), stop.stopPoint().longitude());
132 startLat = stop.stopPoint().latitude();
133 startLon = stop.stopPoint().longitude();
134 }
135
136 dist += Location::distance(startLat, startLon, d->to.latitude(), d->to.longitude());
137 }
138 dist = std::max<double>(dist, d->path.distance());
139 return std::max((int)std::round(dist), d->distance);
140}
141
142void JourneySection::setDistance(int value)
143{
144 d.detach();
145 d->distance = value;
146}
147
149{
150 return d->scheduledDeparturePlatform;
151}
152
153void JourneySection::setScheduledDeparturePlatform(const QString &platform)
154{
155 d.detach();
156 d->scheduledDeparturePlatform = PlatformUtils::normalizePlatform(platform);
157}
158
160{
161 return d->expectedDeparturePlatform;
162}
163
164void JourneySection::setExpectedDeparturePlatform(const QString &platform)
165{
166 d.detach();
167 d->expectedDeparturePlatform = PlatformUtils::normalizePlatform(platform);
168}
169
171{
172 return !d->expectedDeparturePlatform.isEmpty();
173}
174
176{
177 return PlatformUtils::platformChanged(d->scheduledDeparturePlatform, d->expectedDeparturePlatform);
178}
179
181{
182 return d->scheduledArrivalPlatform;
183}
184
185void JourneySection::setScheduledArrivalPlatform(const QString &platform)
186{
187 d.detach();
188 d->scheduledArrivalPlatform = PlatformUtils::normalizePlatform(platform);
189}
190
192{
193 return d->expectedArrivalPlatform;
194}
195
196void JourneySection::setExpectedArrivalPlatform(const QString &platform)
197{
198 d.detach();
199 d->expectedArrivalPlatform = PlatformUtils::normalizePlatform(platform);
200}
201
203{
204 return !d->expectedArrivalPlatform.isEmpty();
205}
206
208{
209 return PlatformUtils::platformChanged(d->scheduledArrivalPlatform, d->expectedArrivalPlatform);
210}
211
213{
214 const auto n = NotesUtil::normalizeNote(note);
215 const auto idx = NotesUtil::needsAdding(d->notes, n);
216 if (idx >= 0) {
217 d.detach();
218 NotesUtil::performAdd(d->notes, n, idx);
219 }
220}
221
222void JourneySection::addNotes(const QStringList &notes)
223{
224 for (const auto &n : notes) {
225 addNote(n);
226 }
227}
228
229const std::vector<Stopover>& JourneySection::intermediateStops() const
230{
231 return d->intermediateStops;
232}
233
235{
236 d.detach();
237 return std::move(d->intermediateStops);
238}
239
240void JourneySection::setIntermediateStops(std::vector<Stopover> &&stops)
241{
242 d.detach();
243 d->intermediateStops = std::move(stops);
244}
245
246QVariantList JourneySection::intermediateStopsVariant() const
247{
248 QVariantList l;
249 l.reserve(d->intermediateStops.size());
250 std::transform(d->intermediateStops.begin(), d->intermediateStops.end(), std::back_inserter(l), [](const auto &stop) { return QVariant::fromValue(stop); });
251 return l;
252}
253
255{
256 Stopover dep;
257 dep.setStopPoint(from());
258 dep.setRoute(route());
259 dep.setScheduledDepartureTime(scheduledDepartureTime());
260 dep.setExpectedDepartureTime(expectedDepartureTime());
261 dep.setScheduledPlatform(scheduledDeparturePlatform());
262 dep.setExpectedPlatform(expectedDeparturePlatform());
263 dep.addNotes(notes());
264 dep.setDisruptionEffect(disruptionEffect());
265 dep.setVehicleLayout(departureVehicleLayout());
266 dep.setPlatformLayout(departurePlatformLayout());
267 return dep;
268}
269
271{
272 setFrom(departure.stopPoint());
273 setScheduledDepartureTime(departure.scheduledDepartureTime());
274 setExpectedDepartureTime(departure.expectedDepartureTime());
275 setScheduledDeparturePlatform(departure.scheduledPlatform());
276 setExpectedDeparturePlatform(departure.expectedPlatform());
277 setDeparturePlatformLayout(departure.platformLayout());
278 setDepartureVehicleLayout(departure.vehicleLayout());
279}
280
282{
283 Stopover arr;
284 arr.setStopPoint(to());
285 arr.setRoute(route());
286 arr.setScheduledArrivalTime(scheduledArrivalTime());
287 arr.setExpectedArrivalTime(expectedArrivalTime());
288 arr.setScheduledPlatform(scheduledArrivalPlatform());
289 arr.setExpectedPlatform(expectedArrivalPlatform());
290 arr.setDisruptionEffect(disruptionEffect());
291 arr.setVehicleLayout(arrivalVehicleLayout());
292 arr.setPlatformLayout(arrivalPlatformLayout());
293 return arr;
294}
295
297{
298 setTo(arrival.stopPoint());
299 setScheduledArrivalTime(arrival.scheduledArrivalTime());
300 setExpectedArrivalTime(arrival.expectedArrivalTime());
301 setScheduledArrivalPlatform(arrival.scheduledPlatform());
302 setExpectedArrivalPlatform(arrival.expectedPlatform());
303 setArrivalPlatformLayout(arrival.platformLayout());
304 setArrivalVehicleLayout(arrival.vehicleLayout());
305}
306
307struct {
308 Line::Mode mode;
309 int gramPerKm;
310} static constexpr const emissionForModeMap[] = {
311 { Line::Air, 285 },
312 { Line::Boat, 245 },
313 { Line::Bus, 68 },
314 { Line::Coach, 68 },
315 { Line::Ferry, 245 },
316 // { Line::Funicular, -1 }, TODO
317 { Line::LocalTrain, 14 },
318 { Line::LongDistanceTrain, 14 },
319 { Line::Metro, 11 },
320 { Line::RailShuttle, 11 }, // assuming tram/rapid transit-like
321 { Line::RapidTransit, 11 },
322 { Line::Shuttle, 68 },
323 { Line::Taxi, 158 },
324 { Line::Train, 14 },
325 { Line::Tramway, 11 },
326 { Line::RideShare, 158 },
327 // { Line::AerialLift, -1 }, TODO
328};
329
330struct {
332 int gramPerKm;
333} static constexpr const emissionForIvModeMap[] = {
334 { IndividualTransport::Walk, 0 },
335 { IndividualTransport::Bike, 0 },
336 { IndividualTransport::Car, 158 }
337};
338
339struct {
341 int gramPerKm;
342} static constexpr const emissionForRvModeMap[] = {
344 // { RentalVehicle::Pedelec, -1 }, TODO
345 // { RentalVehicle::ElectricKickScooter, -1 }, TODO
346 // { RentalVehicle::ElectricMoped, -1 }, TODO
347 { RentalVehicle::Car, 158 },
348};
349
351{
352 if (d->co2Emission >= 0) {
353 return d->co2Emission;
354 }
355
356 switch (d->mode) {
357 case JourneySection::Invalid:
358 return -1;
359 case JourneySection::Walking:
360 case JourneySection::Transfer:
361 case JourneySection::Waiting:
362 return 0;
363 case JourneySection::PublicTransport:
364 {
365 const auto mode = route().line().mode();
366 for (const auto &map : emissionForModeMap) {
367 if (map.mode == mode) {
368 return (map.gramPerKm * distance()) / 1000;
369 }
370 }
371 qCDebug(Log) << "No CO2 emission estimate for mode" << mode;
372 return -1;
373 }
375 {
376 const auto mode = individualTransport().mode();
377 for (const auto &map :emissionForIvModeMap) {
378 if (map.mode == mode) {
379 return (map.gramPerKm *distance()) / 1000;
380 }
381 }
382 qCDebug(Log) << "No CO2 emission estimate for mode" << mode;
383 return -1;
384 }
386 {
387 const auto mode = rentalVehicle().type();
388 for (const auto &map :emissionForRvModeMap) {
389 if (map.mode == mode) {
390 return (map.gramPerKm *distance()) / 1000;
391 }
392 }
393 qCDebug(Log) << "No CO2 emission estimate for vehicle type" << mode;
394 return -1;
395 }
396 }
397
398 return -1;
399}
400
401void JourneySection::setCo2Emission(int value)
402{
403 d.detach();
404 d->co2Emission = value;
405}
406
407const std::vector<LoadInfo>& JourneySection::loadInformation() const
408{
409 return d->loadInformation;
410}
411
412std::vector<LoadInfo>&& JourneySection::takeLoadInformation()
413{
414 d.detach();
415 return std::move(d->loadInformation);
416}
417
418void JourneySection::setLoadInformation(std::vector<LoadInfo> &&loadInfo)
419{
420 d.detach();
421 d->loadInformation = std::move(loadInfo);
422}
423
424QVariantList JourneySection::loadInformationVariant() const
425{
426 QVariantList l;
427 l.reserve(d->loadInformation.size());
428 std::transform(d->loadInformation.begin(), d->loadInformation.end(), std::back_inserter(l), [](const auto &load) { return QVariant::fromValue(load); });
429 return l;
430}
431
432const std::vector<KPublicTransport::Feature>& JourneySection::features() const
433{
434 return d->departureVehicleLayout.features();
435}
436
437[[nodiscard]] std::vector<KPublicTransport::Feature>&& JourneySection::takeFeatures()
438{
439 return d->departureVehicleLayout.takeFeatures();
440}
441
442void JourneySection::setFeatures(std::vector<KPublicTransport::Feature> &&features)
443{
444 d.detach();
445 d->departureVehicleLayout.setFeatures(std::move(features));
446}
447
449{
450 switch (d->mode) {
451 case JourneySection::Invalid:
452 return {};
453 case JourneySection::PublicTransport:
454 return d->route.line().iconName();
456 return d->rentalVehicle.vehicleTypeIconName();
458 return d->individualTransport.modeIconName();
459 case JourneySection::Transfer:
460 case JourneySection::Walking:
461 case JourneySection::Waiting:
462 break;
463 }
464
465 return modeIconName(d->mode);
466}
467
469{
470 switch (mode) {
471 case JourneySection::Invalid:
472 return {};
473 case JourneySection::PublicTransport:
474 return Line::modeIconName(Line::Train);
475 case JourneySection::Transfer:
476 return u"qrc:///org.kde.kpublictransport/assets/images/journey-mode-transfer.svg"_s;
477 case JourneySection::Walking:
478 return IndividualTransport::modeIconName(IndividualTransport::Walk);
479 case JourneySection::Waiting:
480 return u"qrc:///org.kde.kpublictransport/assets/images/journey-mode-wait.svg"_s;
484 return IndividualTransport::modeIconName(IndividualTransport::Bike);
485 }
486
487 return u"question"_s;
488}
489
491{
492 if (!from().hasCoordinate() || mode() != JourneySection::PublicTransport) {
493 return;
494 }
495 auto line = d->route.line();
496 line.applyMetaData(from(), download);
497 d->route.setLine(line);
498
499 // propagate to intermediate stops
500 for (auto &stop : d->intermediateStops) {
501 stop.setRoute(d->route);
502 }
503}
504
506{
507 if (lhs.d->mode != rhs.d->mode) {
508 return false;
509 }
510
512 return false;
513 }
514
515 // we have N criteria to compare here, with 3 possible results:
516 // - equal
517 // - similar-ish, unknwon, or at least not conflicting
518 // - conflicting
519 // A single conflict results in a negative result, at least N - 1 equal comparisons lead to
520 // in a positive result.
521 enum { Equal = 1, Compatible = 0, Conflict = -1000 };
522 int result = 0;
523
524 const auto depTimeDist = MergeUtil::distance(lhs.d->scheduledDepartureTime, rhs.d->scheduledDepartureTime);
525 result += depTimeDist < 60 ? Equal : depTimeDist <= 60 ? Compatible : Conflict;
526 const auto arrTimeDist = MergeUtil::distance(lhs.d->scheduledArrivalTime, rhs.d->scheduledArrivalTime);
527 result += arrTimeDist < 60 ? Equal : depTimeDist <= 60 ? Compatible : Conflict;
528
529 const auto sameFrom = Location::isSame(lhs.d->from, rhs.d->from);
530 const auto fromDist = Location::distance(lhs.from(), rhs.from());
531 result += sameFrom ? Equal : fromDist < 200 ? Compatible : Conflict;
532
533 const auto sameTo = Location::isSame(lhs.d->to, rhs.d->to);
534 const auto toDist = Location::distance(lhs.to(), rhs.to());
535 result += sameTo ? Equal : toDist < 200 ? Compatible : Conflict;
536
537 const auto sameRoute = Route::isSame(lhs.d->route, rhs.d->route);
538 const auto sameDir = Location::isSameName(lhs.d->route.direction(), rhs.d->route.direction());
539 const auto sameLine = Line::isSame(lhs.d->route.line(), rhs.d->route.line());
540 result += sameRoute ? Equal : (sameDir || sameLine) ? Compatible : Conflict;
541
543 result += lhs.scheduledDeparturePlatform() == rhs.scheduledDeparturePlatform() ? Equal : Conflict;
544 }
545
546 return result >= 4;
547}
548
550{
551 using namespace MergeUtil;
552 auto res = lhs;
553 res.setScheduledDepartureTime(mergeDateTimeEqual(lhs.scheduledDepartureTime(), rhs.scheduledDepartureTime()));
554 res.setExpectedDepartureTime(mergeDateTimeMax(lhs.expectedDepartureTime(), rhs.expectedDepartureTime()));
555 res.setScheduledArrivalTime(mergeDateTimeMax(lhs.scheduledArrivalTime(), rhs.scheduledArrivalTime()));
556 res.setExpectedArrivalTime(mergeDateTimeMax(lhs.expectedArrivalTime(), rhs.expectedArrivalTime()));
557
558 if (res.expectedDeparturePlatform().isEmpty()) {
559 res.setExpectedDeparturePlatform(rhs.expectedDeparturePlatform());
560 }
561 if (res.expectedArrivalPlatform().isEmpty()) {
562 res.setExpectedArrivalPlatform(rhs.expectedArrivalPlatform());
563 }
564 res.setFrom(Location::merge(lhs.from(), rhs.from()));
565 res.setTo(Location::merge(lhs.to(), rhs.to()));
566 res.setRoute(Route::merge(lhs.route(), rhs.route()));
567
568 res.setScheduledDeparturePlatform(mergeString(lhs.scheduledDeparturePlatform(), rhs.scheduledDeparturePlatform()));
569 res.setScheduledArrivalPlatform(mergeString(lhs.scheduledArrivalPlatform(), rhs.scheduledArrivalPlatform()));
570
571 res.setDisruptionEffect(std::max(lhs.disruptionEffect(), rhs.disruptionEffect()));
572 res.setNotes(NotesUtil::mergeNotes(lhs.notes(), rhs.notes()));
573 res.setDistance(std::max(lhs.distance(), rhs.distance()));
574
575 if (lhs.intermediateStops().size() == rhs.intermediateStops().size()) {
576 auto stops = res.takeIntermediateStops();
577 for (uint i = 0; i < stops.size(); ++i) {
578 stops[i] = Stopover::merge(stops[i], rhs.intermediateStops()[i]);
579 stops[i].setRoute(res.route());
580 }
581 res.setIntermediateStops(std::move(stops));
582 }
583
584 res.d->co2Emission = std::max(lhs.d->co2Emission, rhs.d->co2Emission);
585 res.d->loadInformation = LoadUtil::merge(lhs.d->loadInformation, rhs.d->loadInformation);
586 res.d->rentalVehicle = RentalVehicleUtil::merge(lhs.d->rentalVehicle, rhs.d->rentalVehicle);
587
588 res.d->path = lhs.d->path.sections().size() < rhs.d->path.sections().size() ? rhs.d->path : lhs.d->path;
589
590 res.d->departureVehicleLayout = Vehicle::merge(lhs.d->departureVehicleLayout, rhs.d->departureVehicleLayout);
591 res.d->departurePlatformLayout = Platform::merge(lhs.d->departurePlatformLayout, rhs.d->departurePlatformLayout);
592 res.d->arrivalVehicleLayout = Vehicle::merge(lhs.d->arrivalVehicleLayout, rhs.d->arrivalVehicleLayout);
593 res.d->arrivalPlatformLayout = Platform::merge(lhs.d->arrivalPlatformLayout, rhs.d->arrivalPlatformLayout);
594
595 return res;
596}
597
599{
600 auto obj = Json::toJson(section);
601 if (section.mode() != Waiting) {
602 const auto fromObj = Location::toJson(section.from());
603 if (!fromObj.empty()) {
604 obj.insert(QLatin1String("from"), fromObj);
605 }
606 const auto toObj = Location::toJson(section.to());
607 if (!toObj.empty()) {
608 obj.insert(QLatin1String("to"), toObj);
609 }
610 }
611 if (section.mode() == PublicTransport) {
612 const auto routeObj = Route::toJson(section.route());
613 if (!routeObj.empty()) {
614 obj.insert(QLatin1String("route"), routeObj);
615 }
616 if (!section.intermediateStops().empty()) {
617 obj.insert(QLatin1String("intermediateStops"), Stopover::toJson(section.intermediateStops()));
618 }
619 if (!section.loadInformation().empty()) {
620 obj.insert(QLatin1String("load"), LoadInfo::toJson(section.loadInformation()));
621 }
622 }
623 if (section.d->co2Emission < 0) {
624 obj.remove(QLatin1String("co2Emission"));
625 }
626 if (section.rentalVehicle().type() != RentalVehicle::Unknown) {
627 obj.insert(QLatin1String("rentalVehicle"), RentalVehicle::toJson(section.rentalVehicle()));
628 }
629
630 if (!section.path().isEmpty()) {
631 obj.insert(QLatin1String("path"), Path::toJson(section.path()));
632 }
633
634 if (!section.departureVehicleLayout().isEmpty()) {
635 obj.insert(QLatin1String("departureVehicleLayout"), Vehicle::toJson(section.departureVehicleLayout()));
636 }
637 if (!section.departurePlatformLayout().isEmpty()) {
638 obj.insert(QLatin1String("departurePlatformLayout"), Platform::toJson(section.departurePlatformLayout()));
639 }
640 if (!section.arrivalVehicleLayout().isEmpty()) {
641 obj.insert(QLatin1String("arrivalVehicleLayout"), Vehicle::toJson(section.arrivalVehicleLayout()));
642 }
643 if (!section.arrivalPlatformLayout().isEmpty()) {
644 obj.insert(QLatin1String("arrivalPlatformLayout"), Platform::toJson(section.arrivalPlatformLayout()));
645 }
646
647 if (section.mode() == JourneySection::IndividualTransport) {
648 obj.insert(QLatin1String("individualTransport"), IndividualTransport::toJson(section.individualTransport()));
649 }
650
651 if (obj.size() <= 3) { // only the disruption and mode enums and distance, ie. this is an empty object
652 return {};
653 }
654 return obj;
655}
656
657QJsonArray JourneySection::toJson(const std::vector<JourneySection> &sections)
658{
659 return Json::toJson(sections);
660}
661
663{
664 auto section = Json::fromJson<JourneySection>(obj);
665 section.setFrom(Location::fromJson(obj.value(QLatin1String("from")).toObject()));
666 section.setTo(Location::fromJson(obj.value(QLatin1String("to")).toObject()));
667 section.setRoute(Route::fromJson(obj.value(QLatin1String("route")).toObject()));
668 section.setIntermediateStops(Stopover::fromJson(obj.value(QLatin1String("intermediateStops")).toArray()));
669 section.setLoadInformation(LoadInfo::fromJson(obj.value(QLatin1String("load")).toArray()));
670 section.setRentalVehicle(RentalVehicle::fromJson(obj.value(QLatin1String("rentalVehicle")).toObject()));
671 section.setPath(Path::fromJson(obj.value(QLatin1String("path")).toObject()));
672 section.setDepartureVehicleLayout(Vehicle::fromJson(obj.value(QLatin1String("departureVehicleLayout")).toObject()));
673 section.setDeparturePlatformLayout(Platform::fromJson(obj.value(QLatin1String("departurePlatformLayout")).toObject()));
674 section.setArrivalVehicleLayout(Vehicle::fromJson(obj.value(QLatin1String("arrivalVehicleLayout")).toObject()));
675 section.setArrivalPlatformLayout(Platform::fromJson(obj.value(QLatin1String("arrivalPlatformLayout")).toObject()));
676 section.setIndividualTransport(IndividualTransport::fromJson(obj.value(QLatin1String("individualTransport")).toObject()));
677 section.applyMetaData(false);
678 return section;
679}
680
681std::vector<JourneySection> JourneySection::fromJson(const QJsonArray &array)
682{
683 return Json::fromJson<JourneySection>(array);
684}
685
686
687KPUBLICTRANSPORT_MAKE_GADGET(Journey)
688
689const std::vector<JourneySection>& Journey::sections() const
690{
691 return d->sections;
692}
693
694std::vector<JourneySection>&& Journey::takeSections()
695{
696 d.detach();
697 return std::move(d->sections);
698}
699
700void Journey::setSections(std::vector<JourneySection> &&sections)
701{
702 d.detach();
703 d->sections = std::move(sections);
704}
705
706QVariantList Journey::sectionsVariant() const
707{
708 QVariantList l;
709 l.reserve(d->sections.size());
710 std::transform(d->sections.begin(), d->sections.end(), std::back_inserter(l), [](const auto &sec) { return QVariant::fromValue(sec); });
711 return l;
712}
713
715{
716 if (!d->sections.empty()) {
717 return d->sections.front().scheduledDepartureTime();
718 }
719 return {};
720}
721
723{
724 return d->sections.empty() ? false : d->sections.front().hasExpectedDepartureTime();
725}
726
728{
729 return d->sections.empty() ? QDateTime() : d->sections.front().expectedDepartureTime();
730}
731
732int Journey::departureDelay() const
733{
734 return d->sections.empty() ? 0 : d->sections.front().departureDelay();
735}
736
738{
739 if (!d->sections.empty()) {
740 return d->sections.back().scheduledArrivalTime();
741 }
742 return {};
743}
744
746{
747 return d->sections.empty() ? false : d->sections.back().hasExpectedArrivalTime();
748}
749
751{
752 return d->sections.empty() ? QDateTime() : d->sections.back().expectedArrivalTime();
753}
754
755int Journey::arrivalDelay() const
756{
757 return d->sections.empty() ? 0 : d->sections.back().arrivalDelay();
758}
759
760int Journey::duration() const
761{
763}
764
765int Journey::numberOfChanges() const
766{
767 return std::max(0, static_cast<int>(std::count_if(d->sections.begin(), d->sections.end(), [](const auto &section) { return section.mode() == JourneySection::PublicTransport; }) - 1));
768}
769
771{
772 Disruption::Effect effect = Disruption::NormalService;
773 for (const auto &sec : d->sections) {
774 effect = std::max(effect, sec.disruptionEffect());
775 }
776 return effect;
777}
778
779int Journey::distance() const
780{
781 return std::accumulate(d->sections.begin(), d->sections.end(), 0, [](auto dist, const auto &jny) { return dist + jny.distance(); });
782}
783
784int Journey::co2Emission() const
785{
786 return std::accumulate(d->sections.begin(), d->sections.end(), 0, [](auto co2, const auto &jny) { return co2 + std::max(0, jny.co2Emission()); });
787}
788
789void Journey::applyMetaData(bool download)
790{
791 for (auto &sec : d->sections) {
792 sec.applyMetaData(download);
793 }
794}
795
796static bool isTransportSection(JourneySection::Mode mode)
797{
798 return mode == JourneySection::PublicTransport
801}
802
803bool Journey::isSame(const Journey &lhs, const Journey &rhs)
804{
805 auto lIt = lhs.sections().begin();
806 auto rIt = rhs.sections().begin();
807
808 while (lIt != lhs.sections().end() || rIt != rhs.sections().end()) {
809 // ignore non-transport sections
810 if (lIt != lhs.sections().end() && !isTransportSection((*lIt).mode())) {
811 ++lIt;
812 continue;
813 }
814 if (rIt != rhs.sections().end() && !isTransportSection((*rIt).mode())) {
815 ++rIt;
816 continue;
817 }
818
819 if (lIt == lhs.sections().end() || rIt == rhs.sections().end()) {
820 return false;
821 }
822
823 if (!JourneySection::isSame(*lIt, *rIt)) {
824 return false;
825 }
826
827 ++lIt;
828 ++rIt;
829 }
830
831 Q_ASSERT(lIt == lhs.sections().end() && rIt == rhs.sections().end());
832 return true;
833}
834
835Journey Journey::merge(const Journey &lhs, const Journey &rhs)
836{
837 std::vector<JourneySection> sections;
838 sections.reserve(lhs.sections().size() + rhs.sections().size());
839 std::copy(lhs.sections().begin(), lhs.sections().end(), std::back_inserter(sections));
840 std::copy(rhs.sections().begin(), rhs.sections().end(), std::back_inserter(sections));
841 std::sort(sections.begin(), sections.end(), [](const auto &lSec, const auto &rSec) {
842 if (MergeUtil::distance(lSec.scheduledDepartureTime(), rSec.scheduledDepartureTime()) == 0) {
843 return lSec.mode() < rSec.mode();
844 }
845 return MergeUtil::isBefore(lSec.scheduledDepartureTime(), rSec.scheduledDepartureTime());
846 });
847
848 for (auto it = sections.begin(); it != sections.end(); ++it) {
849 const auto nextIt = it + 1;
850 if (nextIt == sections.end()) {
851 break;
852 }
853
854 if (JourneySection::isSame(*it, *nextIt) || ((*it).mode() == (*nextIt).mode() && (*it).mode() != JourneySection::PublicTransport)) {
855 *it = JourneySection::merge(*it, *nextIt);
856 sections.erase(nextIt);
857 }
858 }
859
860 Journey res;
861 res.setSections(std::move(sections));
862 return res;
863}
864
866{
867 QJsonObject obj;
868 obj.insert(QLatin1String("sections"), JourneySection::toJson(journey.sections()));
869 return obj;
870}
871
872QJsonArray Journey::toJson(const std::vector<Journey> &journeys)
873{
874 return Json::toJson(journeys);
875}
876
878{
879 Journey j;
880 j.setSections(JourneySection::fromJson(obj.value(QLatin1String("sections")).toArray()));
881 return j;
882}
883
884std::vector<Journey> Journey::fromJson(const QJsonArray &array)
885{
886 return Json::fromJson<Journey>(array);
887}
888
889#include "moc_journey.cpp"
Individual transport mode details for a journey section, and for specifying journey requests.
Mode
Mode of (individual) transportation.
static QJsonObject toJson(const IndividualTransport &it)
Serializes one object to JSON.
static IndividualTransport fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
QString modeIconName
Name of an icon to represent this transport mode.
A segment of a journey plan.
Definition journey.h:32
KPublicTransport::Path path
Movement path for this journey section.
Definition journey.h:141
void applyMetaData(bool download)
Augment line meta data.
Definition journey.cpp:490
bool arrivalPlatformChanged
true if we have real-time platform information and the platform changed.
Definition journey.h:105
QString scheduledDeparturePlatform
Planned departure platform.
Definition journey.h:90
static JourneySection merge(const JourneySection &lhs, const JourneySection &rhs)
Merge two instances.
Definition journey.cpp:549
void setDeparture(const Stopover &departure)
Sets all departure properties from a given Stopover.
Definition journey.cpp:270
static bool isSame(const JourneySection &lhs, const JourneySection &rhs)
Checks if two instances refer to the same journey section (which does not necessarily mean they are e...
Definition journey.cpp:505
void setLoadInformation(std::vector< LoadInfo > &&loadInfo)
Set the vehicle load information for this journey section.
Definition journey.cpp:418
KPublicTransport::Location from
Departure location of this segment.
Definition journey.h:83
QDateTime expectedArrivalTime
Actual arrival time, if available.
Definition journey.h:71
QString expectedArrivalPlatform
Actual arrival platform, in case real-time information are available.
Definition journey.h:101
QString iconName
The best available icon to represent this journey section.
Definition journey.h:167
int departureDelay
Difference to schedule in minutes.
Definition journey.h:64
void setIntermediateStops(std::vector< Stopover > &&stops)
Set the intermediate stops.
Definition journey.cpp:240
static Q_INVOKABLE QString modeIconName(KPublicTransport::JourneySection::Mode mode)
Icon representing the journey section mode mode.
Definition journey.cpp:468
KPublicTransport::Platform arrivalPlatformLayout
Platform layout information at arrival.
Definition journey.h:153
int co2Emission
CO₂ emission during this journey section, in gram.
Definition journey.h:127
KPublicTransport::RentalVehicle rentalVehicle
Information about a rental vehicle, for sections using one.
Definition journey.h:135
QStringList notes
General human-readable notes on this service, e.g.
Definition journey.h:110
void setArrival(const Stopover &arrival)
Sets all arrival properties from a given Stopover.
Definition journey.cpp:296
static QJsonObject toJson(const JourneySection &section)
Serializes one journey section to JSON.
Definition journey.cpp:598
QDateTime scheduledDepartureTime
Planned departure time.
Definition journey.h:56
bool hasExpectedArrivalPlatform
true if real-time platform information are available.
Definition journey.h:103
@ RentedVehicle
free floating or dock-based rental bike service, electric scooters, car sharing services,...
Definition journey.h:45
@ IndividualTransport
using your own vehicle (bike, car, etc).
Definition journey.h:46
KPublicTransport::Route route
Route to take on this segment.
Definition journey.h:87
KPublicTransport::Disruption::Effect disruptionEffect
Disruption effect on this section, if any.
Definition journey.h:108
KPublicTransport::Stopover departure
All departure information represented as Stopover object.
Definition journey.h:116
QVariantList loadInformation
Vehicle load information for this journey section.
Definition journey.h:132
KPublicTransport::Vehicle arrivalVehicleLayout
Vehicle coach layout information at arrival.
Definition journey.h:151
QVariantList intermediateStops
Intermediate stops for consumption by QML.
Definition journey.h:113
KPublicTransport::Platform departurePlatformLayout
Platform layout information at departure.
Definition journey.h:146
int arrivalDelay
Difference to schedule in minutes.
Definition journey.h:75
KPublicTransport::Location to
Arrival location of this segment.
Definition journey.h:85
std::vector< Stopover > && takeIntermediateStops()
Moves the intermediate stops out of this object.
Definition journey.cpp:234
bool hasExpectedDeparturePlatform
true if real-time platform information are available.
Definition journey.h:94
QString scheduledArrivalPlatform
Planned arrival platform.
Definition journey.h:99
bool hasExpectedDepartureTime
true if this has real-time data.
Definition journey.h:62
bool hasExpectedArrivalTime
true if this has real-time data.
Definition journey.h:73
QString expectedDeparturePlatform
Actual departure platform, in case real-time information are available.
Definition journey.h:92
static JourneySection fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition journey.cpp:662
std::vector< LoadInfo > && takeLoadInformation()
Moves the load information out of this object for modification.
Definition journey.cpp:412
KPublicTransport::Vehicle departureVehicleLayout
Vehicle coach layout information at departure.
Definition journey.h:144
std::vector< KPublicTransport::Feature > features
Features of the vehicle used on this section.
Definition journey.h:162
void addNote(const QString &note)
Adds a note.
Definition journey.cpp:212
int duration
Duration of the section in seconds.
Definition journey.h:78
Mode mode
Mode of transport for this section.
Definition journey.h:53
QDateTime scheduledArrivalTime
Planned arrival time.
Definition journey.h:67
KPublicTransport::IndividualTransport individualTransport
Individual transport details for sections using your own vehicle.
Definition journey.h:156
bool departurePlatformChanged
true if we have real-time platform information and the platform changed.
Definition journey.h:96
QDateTime expectedDepartureTime
Actual departure time, if available.
Definition journey.h:60
KPublicTransport::Stopover arrival
All arrival information represented as Stopover object.
Definition journey.h:118
int distance
Distance of the section in meter.
Definition journey.h:80
A journey plan.
Definition journey.h:272
void applyMetaData(bool download)
Augment line meta data.
Definition journey.cpp:789
KPublicTransport::Disruption::Effect disruptionEffect
Worst disruption effect of any of the journey sections.
Definition journey.h:303
static Journey fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition journey.cpp:877
QDateTime expectedDepartureTime
Actual departure time, if available.
Definition journey.h:283
QDateTime scheduledDepartureTime
Departure time of the journey, according to schedule.
Definition journey.h:277
static bool isSame(const Journey &lhs, const Journey &rhs)
Checks if two instances refer to the same journey (which does not necessarily mean they are exactly e...
Definition journey.cpp:803
QVariantList sections
Journey sections for consumption by QML.
Definition journey.h:275
QDateTime expectedArrivalTime
Actual arrival time, if available.
Definition journey.h:294
int departureDelay
Difference to schedule in minutes.
Definition journey.h:285
int numberOfChanges
Number of changes on this journey.
Definition journey.h:301
void setSections(std::vector< JourneySection > &&sections)
Sets the journey sections.
Definition journey.cpp:700
static QJsonObject toJson(const Journey &journey)
Serializes one journey object to JSON.
Definition journey.cpp:865
bool hasExpectedDepartureTime
true if this has real-time data.
Definition journey.h:279
int duration
Duration of the entire journey in seconds.
Definition journey.h:299
QDateTime scheduledArrivalTime
Arrival time of the journey, according to schedule.
Definition journey.h:288
int distance
Total travelled distance of the entire journey in meter.
Definition journey.h:308
int arrivalDelay
Difference to schedule in minutes.
Definition journey.h:296
int co2Emission
Total CO2 emissions for the entire journey in gram.
Definition journey.h:312
std::vector< JourneySection > && takeSections()
Moves the journey sections out of this object.
Definition journey.cpp:694
static Journey merge(const Journey &lhs, const Journey &rhs)
Merge two instances.
Definition journey.cpp:835
bool hasExpectedArrivalTime
true if this has real-time data.
Definition journey.h:290
KPublicTransport::Line::Mode mode
Type of transport.
Definition line.h:60
QString modeIconName
Generic icon for the line mode.
Definition line.h:93
Mode
Mode of transportation.
Definition line.h:27
@ RideShare
peer-to-peer ride sharing/car pooling
Definition line.h:44
@ RailShuttle
rail shuttle service within a complex, as e.g. found at or around airports
Definition line.h:38
@ Shuttle
shuttle bus/coach services, e.g. to/from an airport
Definition line.h:40
static bool isSame(const Line &lhs, const Line &rhs)
Checks if to instances refer to the same line (which does not necessarily mean they are exactly equal...
Definition line.cpp:167
static QJsonObject toJson(const LoadInfo &info)
Serializes one load information object to JSON.
Definition load.cpp:26
static LoadInfo fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition load.cpp:36
static Location fromJson(const QJsonObject &obj)
Deserialize a Location object from JSON.
Definition location.cpp:559
static bool isSameName(const QString &lhs, const QString &rhs)
Checks if two location names refer to the same location.
Definition location.cpp:370
static QJsonObject toJson(const Location &loc)
Serializes one Location object to JSON.
Definition location.cpp:494
static double distance(double lat1, double lon1, double lat2, double lon2)
Compute the distance between two geo coordinates, in meters.
Definition location.cpp:474
static Location merge(const Location &lhs, const Location &rhs)
Merge two departure instances.
Definition location.cpp:417
static bool isSame(const Location &lhs, const Location &rhs)
Checks if to instances refer to the same location (which does not necessarily mean they are exactly e...
Definition location.cpp:311
A path followed by any kind of location change.
Definition path.h:113
bool isEmpty() const
Returns true if this is an empty/not-set path.
Definition path.cpp:143
static Path fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition path.cpp:187
static QJsonObject toJson(const Path &path)
Serializes one path object to JSON.
Definition path.cpp:180
std::vector< KPublicTransport::PathSection > sections
Access to path sections for QML.
Definition path.h:117
Information about the layout of a station platform.
Definition platform.h:45
static Platform fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition platform.cpp:113
bool isEmpty() const
Returns true if this object contains no information beyond default values.
Definition platform.cpp:66
static Platform merge(const Platform &lhs, const Platform &rhs)
Merge two platform instances.
Definition platform.cpp:93
static QJsonObject toJson(const Platform &platform)
Serializes one platform object to JSON.
Definition platform.cpp:99
An individual rental vehicle used on a JourneySection, ie.
@ Car
electrical- or combustion-powered car
@ ElectricKickScooter
"e scooter", electrically assisted kick scooters, not to be confused with motorcycle-like scooters
@ Bicycle
human-powered bicylce
static RentalVehicle fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
static QJsonObject toJson(const RentalVehicle &vehicle)
Serializes one object to JSON.
VehicleType type
Vehicle type.
QString vehicleTypeIconName
Icon representing the vehicle type.
A route of a public transport line.
Definition line.h:148
QString direction
Direction of the route.
Definition line.h:157
static bool isSame(const Route &lhs, const Route &rhs)
Checks if to instances refer to the same route (which does not necessarily mean they are exactly equa...
Definition line.cpp:266
static QJsonObject toJson(const Route &r)
Serializes one object to JSON.
Definition line.cpp:286
static Route merge(const Route &lhs, const Route &rhs)
Merge two Route instances.
Definition line.cpp:276
KPublicTransport::Line line
Line this route belongs to.
Definition line.h:151
static Route fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition line.cpp:299
Information about an arrival and/or departure of a vehicle at a stop area.
Definition stopover.h:26
static Stopover merge(const Stopover &lhs, const Stopover &rhs)
Merge two departure instances.
Definition stopover.cpp:205
QDateTime expectedDepartureTime
Actual departure time, if available.
Definition stopover.h:45
QString expectedPlatform
Actual departure platform, in case real-time information are available.
Definition stopover.h:54
static QJsonObject toJson(const Stopover &stopover)
Serializes one object to JSON.
Definition stopover.cpp:232
KPublicTransport::Location stopPoint
The stop point of this departure.
Definition stopover.h:64
QDateTime expectedArrivalTime
Actual arrival time, if available.
Definition stopover.h:34
QDateTime scheduledArrivalTime
Planned arrival time.
Definition stopover.h:30
static Stopover fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition stopover.cpp:264
KPublicTransport::Vehicle vehicleLayout
Vehicle coach layout information at this stopover.
Definition stopover.h:77
QDateTime scheduledDepartureTime
Planned departure time.
Definition stopover.h:41
KPublicTransport::Platform platformLayout
Platform layout information.
Definition stopover.h:79
QString scheduledPlatform
Planned departure platform.
Definition stopover.h:52
Information about the vehicle used on a journey.
Definition vehicle.h:159
static QJsonObject toJson(const Vehicle &vehicle)
Serializes one vehicle object to JSON.
Definition vehicle.cpp:264
static Vehicle fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition vehicle.cpp:281
bool isEmpty() const
Returns true if this object contains no information beyond the default values.
Definition vehicle.cpp:176
static Vehicle merge(const Vehicle &lhs, const Vehicle &rhs)
Merge two Vehicle instances.
Definition vehicle.cpp:240
void stop(Ekos::AlignState mode)
Effect
Disruption effects, numerical sorted so that higher values imply more severe disruptions.
Definition disruption.h:25
Query operations and data types for accessing realtime public transport information from online servi...
const QList< QKeySequence > & back()
qint64 secsTo(const QDateTime &other) const const
iterator insert(QLatin1StringView key, const QJsonValue &value)
QJsonValue value(QLatin1StringView key) const const
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 Dec 6 2024 11:59:34 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.