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 "mergeutil_p.h"
13#include "notesutil_p.h"
14#include "platformutils_p.h"
15#include "rentalvehicle.h"
16#include "rentalvehicleutil_p.h"
17#include "stopover.h"
18
19#include <QDebug>
20#include <QVariant>
21
22using namespace Qt::Literals::StringLiterals;
23using namespace KPublicTransport;
24
25namespace KPublicTransport {
26
27class JourneySectionPrivate : public QSharedData
28{
29public:
30 JourneySection::Mode mode = JourneySection::Invalid;
31 QDateTime scheduledDepartureTime;
32 QDateTime expectedDepartureTime;
33 QDateTime scheduledArrivalTime;
34 QDateTime expectedArrivalTime;
35 Location from;
36 Location to;
37 Route route;
38 QString scheduledDeparturePlatform;
39 QString expectedDeparturePlatform;
40 QString scheduledArrivalPlatform;
41 QString expectedArrivalPlatform;
42 int distance = 0;
43 Disruption::Effect disruptionEffect = Disruption::NormalService;
44 QStringList notes;
45 std::vector<Stopover> intermediateStops;
46 int co2Emission = -1;
47 std::vector<LoadInfo> loadInformation;
48 RentalVehicle rentalVehicle;
49 Path path;
50 Vehicle departureVehicleLayout;
51 Platform departurePlatformLayout;
52 Vehicle arrivalVehicleLayout;
53 Platform arrivalPlatformLayout;
54 IndividualTransport individualTransport;
55};
56
57class JourneyPrivate : public QSharedData
58{
59public:
60 std::vector<JourneySection> sections;
61};
62
63}
64
65KPUBLICTRANSPORT_MAKE_GADGET(JourneySection)
66KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, JourneySection::Mode, mode, setMode)
67KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, scheduledDepartureTime, setScheduledDepartureTime)
68KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, expectedDepartureTime, setExpectedDepartureTime)
69KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, scheduledArrivalTime, setScheduledArrivalTime)
70KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, expectedArrivalTime, setExpectedArrivalTime)
71KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Location, from, setFrom)
72KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Location, to, setTo)
73KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Route, route, setRoute)
74KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Disruption::Effect, disruptionEffect, setDisruptionEffect)
75KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QStringList, notes, setNotes)
76KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, RentalVehicle, rentalVehicle, setRentalVehicle)
77KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Path, path, setPath)
78KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Vehicle, departureVehicleLayout, setDepartureVehicleLayout)
79KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Platform, departurePlatformLayout, setDeparturePlatformLayout)
80KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Vehicle, arrivalVehicleLayout, setArrivalVehicleLayout)
81KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Platform, arrivalPlatformLayout, setArrivalPlatformLayout)
82KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, KPublicTransport::IndividualTransport, individualTransport, setIndividualTransport)
83
85{
86 return d->expectedDepartureTime.isValid();
87}
88
90{
92 return d->scheduledDepartureTime.secsTo(d->expectedDepartureTime) / 60;
93 }
94 return 0;
95}
96
98{
99 return d->expectedArrivalTime.isValid();
100}
101
103{
105 return d->scheduledArrivalTime.secsTo(d->expectedArrivalTime) / 60;
106 }
107 return 0;
108}
109
110int JourneySection::duration() const
111{
112 return d->scheduledDepartureTime.secsTo(d->scheduledArrivalTime);
113}
114
115int JourneySection::distance() const
116{
117 if (d->mode == JourneySection::Waiting) {
118 return 0;
119 }
120
121 int dist = 0;
122 if (d->from.hasCoordinate() && d->to.hasCoordinate()) {
123 float startLat = d->from.latitude();
124 float startLon = d->from.longitude();
125
126 for (const auto &stop : d->intermediateStops) {
127 if (!stop.stopPoint().hasCoordinate()) {
128 continue;
129 }
130 dist += Location::distance(startLat, startLon, stop.stopPoint().latitude(), stop.stopPoint().longitude());
131 startLat = stop.stopPoint().latitude();
132 startLon = stop.stopPoint().longitude();
133 }
134
135 dist += Location::distance(startLat, startLon, d->to.latitude(), d->to.longitude());
136 }
137 dist = std::max(dist, d->path.distance());
138 return std::max(dist, d->distance);
139}
140
141void JourneySection::setDistance(int value)
142{
143 d.detach();
144 d->distance = value;
145}
146
148{
149 return d->scheduledDeparturePlatform;
150}
151
152void JourneySection::setScheduledDeparturePlatform(const QString &platform)
153{
154 d.detach();
155 d->scheduledDeparturePlatform = PlatformUtils::normalizePlatform(platform);
156}
157
159{
160 return d->expectedDeparturePlatform;
161}
162
163void JourneySection::setExpectedDeparturePlatform(const QString &platform)
164{
165 d.detach();
166 d->expectedDeparturePlatform = PlatformUtils::normalizePlatform(platform);
167}
168
170{
171 return !d->expectedDeparturePlatform.isEmpty();
172}
173
175{
176 return PlatformUtils::platformChanged(d->scheduledDeparturePlatform, d->expectedDeparturePlatform);
177}
178
180{
181 return d->scheduledArrivalPlatform;
182}
183
184void JourneySection::setScheduledArrivalPlatform(const QString &platform)
185{
186 d.detach();
187 d->scheduledArrivalPlatform = PlatformUtils::normalizePlatform(platform);
188}
189
191{
192 return d->expectedArrivalPlatform;
193}
194
195void JourneySection::setExpectedArrivalPlatform(const QString &platform)
196{
197 d.detach();
198 d->expectedArrivalPlatform = PlatformUtils::normalizePlatform(platform);
199}
200
202{
203 return !d->expectedArrivalPlatform.isEmpty();
204}
205
207{
208 return PlatformUtils::platformChanged(d->scheduledArrivalPlatform, d->expectedArrivalPlatform);
209}
210
212{
213 const auto n = NotesUtil::normalizeNote(note);
214 const auto idx = NotesUtil::needsAdding(d->notes, n);
215 if (idx >= 0) {
216 d.detach();
217 NotesUtil::performAdd(d->notes, n, idx);
218 }
219}
220
221void JourneySection::addNotes(const QStringList &notes)
222{
223 for (const auto &n : notes) {
224 addNote(n);
225 }
226}
227
228const std::vector<Stopover>& JourneySection::intermediateStops() const
229{
230 return d->intermediateStops;
231}
232
234{
235 d.detach();
236 return std::move(d->intermediateStops);
237}
238
239void JourneySection::setIntermediateStops(std::vector<Stopover> &&stops)
240{
241 d.detach();
242 d->intermediateStops = std::move(stops);
243}
244
245QVariantList JourneySection::intermediateStopsVariant() const
246{
247 QVariantList l;
248 l.reserve(d->intermediateStops.size());
249 std::transform(d->intermediateStops.begin(), d->intermediateStops.end(), std::back_inserter(l), [](const auto &stop) { return QVariant::fromValue(stop); });
250 return l;
251}
252
254{
255 Stopover dep;
256 dep.setStopPoint(from());
257 dep.setRoute(route());
258 dep.setScheduledDepartureTime(scheduledDepartureTime());
259 dep.setExpectedDepartureTime(expectedDepartureTime());
260 dep.setScheduledPlatform(scheduledDeparturePlatform());
261 dep.setExpectedPlatform(expectedDeparturePlatform());
262 dep.addNotes(notes());
263 dep.setDisruptionEffect(disruptionEffect());
264 dep.setVehicleLayout(departureVehicleLayout());
265 dep.setPlatformLayout(departurePlatformLayout());
266 return dep;
267}
268
270{
271 setFrom(departure.stopPoint());
272 setScheduledDepartureTime(departure.scheduledDepartureTime());
273 setExpectedDepartureTime(departure.expectedDepartureTime());
274 setScheduledDeparturePlatform(departure.scheduledPlatform());
275 setExpectedDeparturePlatform(departure.expectedPlatform());
276 setDeparturePlatformLayout(departure.platformLayout());
277 setDepartureVehicleLayout(departure.vehicleLayout());
278}
279
281{
282 Stopover arr;
283 arr.setStopPoint(to());
284 arr.setRoute(route());
285 arr.setScheduledArrivalTime(scheduledArrivalTime());
286 arr.setExpectedArrivalTime(expectedArrivalTime());
287 arr.setScheduledPlatform(scheduledArrivalPlatform());
288 arr.setExpectedPlatform(expectedArrivalPlatform());
289 arr.setDisruptionEffect(disruptionEffect());
290 arr.setVehicleLayout(arrivalVehicleLayout());
291 arr.setPlatformLayout(arrivalPlatformLayout());
292 return arr;
293}
294
296{
297 setTo(arrival.stopPoint());
298 setScheduledArrivalTime(arrival.scheduledArrivalTime());
299 setExpectedArrivalTime(arrival.expectedArrivalTime());
300 setScheduledArrivalPlatform(arrival.scheduledPlatform());
301 setExpectedArrivalPlatform(arrival.expectedPlatform());
302 setArrivalPlatformLayout(arrival.platformLayout());
303 setArrivalVehicleLayout(arrival.vehicleLayout());
304}
305
307{
308 // TODO handle rental vehicles and ride sharing in here!
309 if (d->co2Emission >= 0) {
310 return d->co2Emission;
311 }
312
313 struct {
315 int gramPerKm;
316 } static const emissionForModeMap[] = {
317 { Line::Air, 285 },
318 { Line::Boat, 245 },
319 { Line::Bus, 68 },
320 { Line::BusRapidTransit, 68 },
321 { Line::Coach, 68 },
322 { Line::Ferry, 245 },
323 { Line::LocalTrain, 14 },
324 { Line::LongDistanceTrain, 14 },
325 { Line::Metro, 11 },
326 { Line::RapidTransit, 11 },
327 { Line::Taxi, 158 },
328 { Line::Train, 14 },
329 { Line::Tramway, 11 },
330 };
331
332 const auto mode = route().line().mode();
333 for (const auto &map : emissionForModeMap) {
334 if (map.mode == mode) {
335 return (map.gramPerKm * distance()) / 1000;
336 }
337 }
338 return -1;
339}
340
341void JourneySection::setCo2Emission(int value)
342{
343 d.detach();
344 d->co2Emission = value;
345}
346
347const std::vector<LoadInfo>& JourneySection::loadInformation() const
348{
349 return d->loadInformation;
350}
351
352std::vector<LoadInfo>&& JourneySection::takeLoadInformation()
353{
354 d.detach();
355 return std::move(d->loadInformation);
356}
357
358void JourneySection::setLoadInformation(std::vector<LoadInfo> &&loadInfo)
359{
360 d.detach();
361 d->loadInformation = std::move(loadInfo);
362}
363
364QVariantList JourneySection::loadInformationVariant() const
365{
366 QVariantList l;
367 l.reserve(d->loadInformation.size());
368 std::transform(d->loadInformation.begin(), d->loadInformation.end(), std::back_inserter(l), [](const auto &load) { return QVariant::fromValue(load); });
369 return l;
370}
371
372const std::vector<KPublicTransport::Feature>& JourneySection::features() const
373{
374 return d->departureVehicleLayout.features();
375}
376
377[[nodiscard]] std::vector<KPublicTransport::Feature>&& JourneySection::takeFeatures()
378{
379 return d->departureVehicleLayout.takeFeatures();
380}
381
382void JourneySection::setFeatures(std::vector<KPublicTransport::Feature> &&features)
383{
384 d.detach();
385 d->departureVehicleLayout.setFeatures(std::move(features));
386}
387
389{
390 switch (d->mode) {
391 case JourneySection::Invalid:
392 return {};
393 case JourneySection::PublicTransport:
394 return d->route.line().iconName();
396 return d->rentalVehicle.vehicleTypeIconName();
398 return d->individualTransport.modeIconName();
399 case JourneySection::Transfer:
400 case JourneySection::Walking:
401 case JourneySection::Waiting:
402 break;
403 }
404
405 return modeIconName(d->mode);
406}
407
409{
410 switch (mode) {
411 case JourneySection::Invalid:
412 return {};
413 case JourneySection::PublicTransport:
414 return Line::modeIconName(Line::Train);
415 case JourneySection::Transfer:
416 return u"qrc:///org.kde.kpublictransport/assets/images/journey-mode-transfer.svg"_s;
417 case JourneySection::Walking:
418 return IndividualTransport::modeIconName(IndividualTransport::Walk);
419 case JourneySection::Waiting:
420 return u"qrc:///org.kde.kpublictransport/assets/images/journey-mode-wait.svg"_s;
424 return IndividualTransport::modeIconName(IndividualTransport::Bike);
425 }
426
427 return u"question"_s;
428}
429
431{
432 if (!from().hasCoordinate() || mode() != JourneySection::PublicTransport) {
433 return;
434 }
435 auto line = d->route.line();
436 line.applyMetaData(from(), download);
437 d->route.setLine(line);
438
439 // propagate to intermediate stops
440 for (auto &stop : d->intermediateStops) {
441 stop.setRoute(d->route);
442 }
443}
444
446{
447 if (lhs.d->mode != rhs.d->mode) {
448 return false;
449 }
450
452 return false;
453 }
454
455 // we have N criteria to compare here, with 3 possible results:
456 // - equal
457 // - similar-ish, unknwon, or at least not conflicting
458 // - conflicting
459 // A single conflict results in a negative result, at least N - 1 equal comparisons lead to
460 // in a positive result.
461 enum { Equal = 1, Compatible = 0, Conflict = -1000 };
462 int result = 0;
463
464 const auto depTimeDist = MergeUtil::distance(lhs.d->scheduledDepartureTime, rhs.d->scheduledDepartureTime);
465 result += depTimeDist < 60 ? Equal : depTimeDist <= 60 ? Compatible : Conflict;
466 const auto arrTimeDist = MergeUtil::distance(lhs.d->scheduledArrivalTime, rhs.d->scheduledArrivalTime);
467 result += arrTimeDist < 60 ? Equal : depTimeDist <= 60 ? Compatible : Conflict;
468
469 const auto sameFrom = Location::isSame(lhs.d->from, rhs.d->from);
470 const auto fromDist = Location::distance(lhs.from(), rhs.from());
471 result += sameFrom ? Equal : fromDist < 200 ? Compatible : Conflict;
472
473 const auto sameTo = Location::isSame(lhs.d->to, rhs.d->to);
474 const auto toDist = Location::distance(lhs.to(), rhs.to());
475 result += sameTo ? Equal : toDist < 200 ? Compatible : Conflict;
476
477 const auto sameRoute = Route::isSame(lhs.d->route, rhs.d->route);
478 const auto sameDir = Location::isSameName(lhs.d->route.direction(), rhs.d->route.direction());
479 const auto sameLine = Line::isSame(lhs.d->route.line(), rhs.d->route.line());
480 result += sameRoute ? Equal : (sameDir || sameLine) ? Compatible : Conflict;
481
483 result += lhs.scheduledDeparturePlatform() == rhs.scheduledDeparturePlatform() ? Equal : Conflict;
484 }
485
486 return result >= 4;
487}
488
490{
491 using namespace MergeUtil;
492 auto res = lhs;
493 res.setScheduledDepartureTime(mergeDateTimeEqual(lhs.scheduledDepartureTime(), rhs.scheduledDepartureTime()));
494 res.setExpectedDepartureTime(mergeDateTimeMax(lhs.expectedDepartureTime(), rhs.expectedDepartureTime()));
495 res.setScheduledArrivalTime(mergeDateTimeMax(lhs.scheduledArrivalTime(), rhs.scheduledArrivalTime()));
496 res.setExpectedArrivalTime(mergeDateTimeMax(lhs.expectedArrivalTime(), rhs.expectedArrivalTime()));
497
498 if (res.expectedDeparturePlatform().isEmpty()) {
499 res.setExpectedDeparturePlatform(rhs.expectedDeparturePlatform());
500 }
501 if (res.expectedArrivalPlatform().isEmpty()) {
502 res.setExpectedArrivalPlatform(rhs.expectedArrivalPlatform());
503 }
504 res.setFrom(Location::merge(lhs.from(), rhs.from()));
505 res.setTo(Location::merge(lhs.to(), rhs.to()));
506 res.setRoute(Route::merge(lhs.route(), rhs.route()));
507
508 res.setScheduledDeparturePlatform(mergeString(lhs.scheduledDeparturePlatform(), rhs.scheduledDeparturePlatform()));
509 res.setScheduledArrivalPlatform(mergeString(lhs.scheduledArrivalPlatform(), rhs.scheduledArrivalPlatform()));
510
511 res.setDisruptionEffect(std::max(lhs.disruptionEffect(), rhs.disruptionEffect()));
512 res.setNotes(NotesUtil::mergeNotes(lhs.notes(), rhs.notes()));
513 res.setDistance(std::max(lhs.distance(), rhs.distance()));
514
515 if (lhs.intermediateStops().size() == rhs.intermediateStops().size()) {
516 auto stops = res.takeIntermediateStops();
517 for (uint i = 0; i < stops.size(); ++i) {
518 stops[i] = Stopover::merge(stops[i], rhs.intermediateStops()[i]);
519 stops[i].setRoute(res.route());
520 }
521 res.setIntermediateStops(std::move(stops));
522 }
523
524 res.d->co2Emission = std::max(lhs.d->co2Emission, rhs.d->co2Emission);
525 res.d->loadInformation = LoadUtil::merge(lhs.d->loadInformation, rhs.d->loadInformation);
526 res.d->rentalVehicle = RentalVehicleUtil::merge(lhs.d->rentalVehicle, rhs.d->rentalVehicle);
527
528 res.d->path = lhs.d->path.sections().size() < rhs.d->path.sections().size() ? rhs.d->path : lhs.d->path;
529
530 res.d->departureVehicleLayout = Vehicle::merge(lhs.d->departureVehicleLayout, rhs.d->departureVehicleLayout);
531 res.d->departurePlatformLayout = Platform::merge(lhs.d->departurePlatformLayout, rhs.d->departurePlatformLayout);
532 res.d->arrivalVehicleLayout = Vehicle::merge(lhs.d->arrivalVehicleLayout, rhs.d->arrivalVehicleLayout);
533 res.d->arrivalPlatformLayout = Platform::merge(lhs.d->arrivalPlatformLayout, rhs.d->arrivalPlatformLayout);
534
535 return res;
536}
537
539{
540 auto obj = Json::toJson(section);
541 if (section.mode() != Waiting) {
542 const auto fromObj = Location::toJson(section.from());
543 if (!fromObj.empty()) {
544 obj.insert(QLatin1String("from"), fromObj);
545 }
546 const auto toObj = Location::toJson(section.to());
547 if (!toObj.empty()) {
548 obj.insert(QLatin1String("to"), toObj);
549 }
550 }
551 if (section.mode() == PublicTransport) {
552 const auto routeObj = Route::toJson(section.route());
553 if (!routeObj.empty()) {
554 obj.insert(QLatin1String("route"), routeObj);
555 }
556 if (!section.intermediateStops().empty()) {
557 obj.insert(QLatin1String("intermediateStops"), Stopover::toJson(section.intermediateStops()));
558 }
559 if (!section.loadInformation().empty()) {
560 obj.insert(QLatin1String("load"), LoadInfo::toJson(section.loadInformation()));
561 }
562 }
563 if (section.d->co2Emission < 0) {
564 obj.remove(QLatin1String("co2Emission"));
565 }
566 if (section.rentalVehicle().type() != RentalVehicle::Unknown) {
567 obj.insert(QLatin1String("rentalVehicle"), RentalVehicle::toJson(section.rentalVehicle()));
568 }
569
570 if (!section.path().isEmpty()) {
571 obj.insert(QLatin1String("path"), Path::toJson(section.path()));
572 }
573
574 if (!section.departureVehicleLayout().isEmpty()) {
575 obj.insert(QLatin1String("departureVehicleLayout"), Vehicle::toJson(section.departureVehicleLayout()));
576 }
577 if (!section.departurePlatformLayout().isEmpty()) {
578 obj.insert(QLatin1String("departurePlatformLayout"), Platform::toJson(section.departurePlatformLayout()));
579 }
580 if (!section.arrivalVehicleLayout().isEmpty()) {
581 obj.insert(QLatin1String("arrivalVehicleLayout"), Vehicle::toJson(section.arrivalVehicleLayout()));
582 }
583 if (!section.arrivalPlatformLayout().isEmpty()) {
584 obj.insert(QLatin1String("arrivalPlatformLayout"), Platform::toJson(section.arrivalPlatformLayout()));
585 }
586
587 if (section.mode() == JourneySection::IndividualTransport) {
588 obj.insert(QLatin1String("individualTransport"), IndividualTransport::toJson(section.individualTransport()));
589 }
590
591 if (obj.size() <= 3) { // only the disruption and mode enums and distance, ie. this is an empty object
592 return {};
593 }
594 return obj;
595}
596
597QJsonArray JourneySection::toJson(const std::vector<JourneySection> &sections)
598{
599 return Json::toJson(sections);
600}
601
603{
604 auto section = Json::fromJson<JourneySection>(obj);
605 section.setFrom(Location::fromJson(obj.value(QLatin1String("from")).toObject()));
606 section.setTo(Location::fromJson(obj.value(QLatin1String("to")).toObject()));
607 section.setRoute(Route::fromJson(obj.value(QLatin1String("route")).toObject()));
608 section.setIntermediateStops(Stopover::fromJson(obj.value(QLatin1String("intermediateStops")).toArray()));
609 section.setLoadInformation(LoadInfo::fromJson(obj.value(QLatin1String("load")).toArray()));
610 section.setRentalVehicle(RentalVehicle::fromJson(obj.value(QLatin1String("rentalVehicle")).toObject()));
611 section.setPath(Path::fromJson(obj.value(QLatin1String("path")).toObject()));
612 section.setDepartureVehicleLayout(Vehicle::fromJson(obj.value(QLatin1String("departureVehicleLayout")).toObject()));
613 section.setDeparturePlatformLayout(Platform::fromJson(obj.value(QLatin1String("departurePlatformLayout")).toObject()));
614 section.setArrivalVehicleLayout(Vehicle::fromJson(obj.value(QLatin1String("arrivalVehicleLayout")).toObject()));
615 section.setArrivalPlatformLayout(Platform::fromJson(obj.value(QLatin1String("arrivalPlatformLayout")).toObject()));
616 section.setIndividualTransport(IndividualTransport::fromJson(obj.value(QLatin1String("individualTransport")).toObject()));
617 section.applyMetaData(false);
618 return section;
619}
620
621std::vector<JourneySection> JourneySection::fromJson(const QJsonArray &array)
622{
623 return Json::fromJson<JourneySection>(array);
624}
625
626
627KPUBLICTRANSPORT_MAKE_GADGET(Journey)
628
629const std::vector<JourneySection>& Journey::sections() const
630{
631 return d->sections;
632}
633
634std::vector<JourneySection>&& Journey::takeSections()
635{
636 d.detach();
637 return std::move(d->sections);
638}
639
640void Journey::setSections(std::vector<JourneySection> &&sections)
641{
642 d.detach();
643 d->sections = std::move(sections);
644}
645
646QVariantList Journey::sectionsVariant() const
647{
648 QVariantList l;
649 l.reserve(d->sections.size());
650 std::transform(d->sections.begin(), d->sections.end(), std::back_inserter(l), [](const auto &sec) { return QVariant::fromValue(sec); });
651 return l;
652}
653
655{
656 if (!d->sections.empty()) {
657 return d->sections.front().scheduledDepartureTime();
658 }
659 return {};
660}
661
663{
664 return d->sections.empty() ? false : d->sections.front().hasExpectedDepartureTime();
665}
666
668{
669 return d->sections.empty() ? QDateTime() : d->sections.front().expectedDepartureTime();
670}
671
672int Journey::departureDelay() const
673{
674 return d->sections.empty() ? 0 : d->sections.front().departureDelay();
675}
676
678{
679 if (!d->sections.empty()) {
680 return d->sections.back().scheduledArrivalTime();
681 }
682 return {};
683}
684
686{
687 return d->sections.empty() ? false : d->sections.back().hasExpectedArrivalTime();
688}
689
691{
692 return d->sections.empty() ? QDateTime() : d->sections.back().expectedArrivalTime();
693}
694
695int Journey::arrivalDelay() const
696{
697 return d->sections.empty() ? 0 : d->sections.back().arrivalDelay();
698}
699
700int Journey::duration() const
701{
703}
704
705int Journey::numberOfChanges() const
706{
707 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));
708}
709
711{
712 Disruption::Effect effect = Disruption::NormalService;
713 for (const auto &sec : d->sections) {
714 effect = std::max(effect, sec.disruptionEffect());
715 }
716 return effect;
717}
718
719void Journey::applyMetaData(bool download)
720{
721 for (auto &sec : d->sections) {
722 sec.applyMetaData(download);
723 }
724}
725
726static bool isTransportSection(JourneySection::Mode mode)
727{
728 return mode == JourneySection::PublicTransport
731}
732
733bool Journey::isSame(const Journey &lhs, const Journey &rhs)
734{
735 auto lIt = lhs.sections().begin();
736 auto rIt = rhs.sections().begin();
737
738 while (lIt != lhs.sections().end() || rIt != rhs.sections().end()) {
739 // ignore non-transport sections
740 if (lIt != lhs.sections().end() && !isTransportSection((*lIt).mode())) {
741 ++lIt;
742 continue;
743 }
744 if (rIt != rhs.sections().end() && !isTransportSection((*rIt).mode())) {
745 ++rIt;
746 continue;
747 }
748
749 if (lIt == lhs.sections().end() || rIt == rhs.sections().end()) {
750 return false;
751 }
752
753 if (!JourneySection::isSame(*lIt, *rIt)) {
754 return false;
755 }
756
757 ++lIt;
758 ++rIt;
759 }
760
761 Q_ASSERT(lIt == lhs.sections().end() && rIt == rhs.sections().end());
762 return true;
763}
764
765Journey Journey::merge(const Journey &lhs, const Journey &rhs)
766{
767 std::vector<JourneySection> sections;
768 sections.reserve(lhs.sections().size() + rhs.sections().size());
769 std::copy(lhs.sections().begin(), lhs.sections().end(), std::back_inserter(sections));
770 std::copy(rhs.sections().begin(), rhs.sections().end(), std::back_inserter(sections));
771 std::sort(sections.begin(), sections.end(), [](const auto &lSec, const auto &rSec) {
772 if (MergeUtil::distance(lSec.scheduledDepartureTime(), rSec.scheduledDepartureTime()) == 0) {
773 return lSec.mode() < rSec.mode();
774 }
775 return MergeUtil::isBefore(lSec.scheduledDepartureTime(), rSec.scheduledDepartureTime());
776 });
777
778 for (auto it = sections.begin(); it != sections.end(); ++it) {
779 const auto nextIt = it + 1;
780 if (nextIt == sections.end()) {
781 break;
782 }
783
784 if (JourneySection::isSame(*it, *nextIt) || ((*it).mode() == (*nextIt).mode() && (*it).mode() != JourneySection::PublicTransport)) {
785 *it = JourneySection::merge(*it, *nextIt);
786 sections.erase(nextIt);
787 }
788 }
789
790 Journey res;
791 res.setSections(std::move(sections));
792 return res;
793}
794
796{
797 QJsonObject obj;
798 obj.insert(QLatin1String("sections"), JourneySection::toJson(journey.sections()));
799 return obj;
800}
801
802QJsonArray Journey::toJson(const std::vector<Journey> &journeys)
803{
804 return Json::toJson(journeys);
805}
806
808{
809 Journey j;
810 j.setSections(JourneySection::fromJson(obj.value(QLatin1String("sections")).toArray()));
811 return j;
812}
813
814std::vector<Journey> Journey::fromJson(const QJsonArray &array)
815{
816 return Json::fromJson<Journey>(array);
817}
818
819#include "moc_journey.cpp"
Individual transport mode details for a journey section, and for specifying journey requests.
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:430
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:489
void setDeparture(const Stopover &departure)
Sets all departure properties from a given Stopover.
Definition journey.cpp:269
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:445
void setLoadInformation(std::vector< LoadInfo > &&loadInfo)
Set the vehicle load information for this journey section.
Definition journey.cpp:358
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:239
static Q_INVOKABLE QString modeIconName(KPublicTransport::JourneySection::Mode mode)
Icon representing the journey section mode mode.
Definition journey.cpp:408
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:295
static QJsonObject toJson(const JourneySection &section)
Serializes one journey section to JSON.
Definition journey.cpp:538
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:233
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:602
std::vector< LoadInfo > && takeLoadInformation()
Moves the load information out of this object for modification.
Definition journey.cpp:352
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:211
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:719
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:807
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:733
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:640
static QJsonObject toJson(const Journey &journey)
Serializes one journey object to JSON.
Definition journey.cpp:795
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 arrivalDelay
Difference to schedule in minutes.
Definition journey.h:296
std::vector< JourneySection > && takeSections()
Moves the journey sections out of this object.
Definition journey.cpp:634
static Journey merge(const Journey &lhs, const Journey &rhs)
Merge two instances.
Definition journey.cpp:765
bool hasExpectedArrivalTime
true if this has real-time data.
Definition journey.h:290
KPublicTransport::Line::Mode mode
Type of transport.
Definition line.h:61
QString modeIconName
Generic icon for the line mode.
Definition line.h:94
Mode
Mode of transportation.
Definition line.h:27
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:151
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:550
static bool isSameName(const QString &lhs, const QString &rhs)
Checks if two location names refer to the same location.
Definition location.cpp:364
static QJsonObject toJson(const Location &loc)
Serializes one Location object to JSON.
Definition location.cpp:488
static float distance(float lat1, float lon1, float lat2, float lon2)
Compute the distance between two geo coordinates, in meters.
Definition location.cpp:468
static Location merge(const Location &lhs, const Location &rhs)
Merge two departure instances.
Definition location.cpp:411
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:305
A path followed by any kind of location change.
Definition path.h:101
bool isEmpty() const
Returns true if this is an empty/not-set path.
Definition path.cpp:131
static Path fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition path.cpp:175
static QJsonObject toJson(const Path &path)
Serializes one path object to JSON.
Definition path.cpp:168
std::vector< KPublicTransport::PathSection > sections
Access to path sections for QML.
Definition path.h:105
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.
@ ElectricKickScooter
"e scooter", electrically assisted kick scooters, not to be confused with motorcycle-like scooters
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:146
QString direction
Direction of the route.
Definition line.h:155
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:250
static QJsonObject toJson(const Route &r)
Serializes one object to JSON.
Definition line.cpp:270
static Route merge(const Route &lhs, const Route &rhs)
Merge two Route instances.
Definition line.cpp:260
KPublicTransport::Line line
Line this route belongs to.
Definition line.h:149
static Route fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition line.cpp:283
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:186
static QJsonObject toJson(const Vehicle &vehicle)
Serializes one vehicle object to JSON.
Definition vehicle.cpp:340
static Vehicle fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition vehicle.cpp:357
bool isEmpty() const
Returns true if this object contains no information beyond the default values.
Definition vehicle.cpp:252
static Vehicle merge(const Vehicle &lhs, const Vehicle &rhs)
Merge two Vehicle instances.
Definition vehicle.cpp:316
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...
KGuiItem back(BidiMode useBidi=IgnoreRTL)
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 Oct 11 2024 12:12:54 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.