KPublicTransport

journey.cpp
1 /*
2  SPDX-FileCopyrightText: 2018 Volker Krause <[email protected]>
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 
22 using namespace KPublicTransport;
23 
24 namespace KPublicTransport {
25 
26 class JourneySectionPrivate : public QSharedData
27 {
28 public:
29  JourneySection::Mode mode = JourneySection::Invalid;
30  QDateTime scheduledDepartureTime;
31  QDateTime expectedDepartureTime;
32  QDateTime scheduledArrivalTime;
33  QDateTime expectedArrivalTime;
34  Location from;
35  Location to;
36  Route route;
37  QString scheduledDeparturePlatform;
38  QString expectedDeparturePlatform;
39  QString scheduledArrivalPlatform;
40  QString expectedArrivalPlatform;
41  int distance = 0;
42  Disruption::Effect disruptionEffect = Disruption::NormalService;
43  QStringList notes;
44  std::vector<Stopover> intermediateStops;
45  int co2Emission = -1;
46  std::vector<LoadInfo> loadInformation;
47  RentalVehicle rentalVehicle;
48  Path path;
49  Vehicle departureVehicleLayout;
50  Platform departurePlatformLayout;
51  Vehicle arrivalVehicleLayout;
52  Platform arrivalPlatformLayout;
53  IndividualTransport individualTransport;
54 };
55 
56 class JourneyPrivate : public QSharedData
57 {
58 public:
59  std::vector<JourneySection> sections;
60 };
61 
62 }
63 
64 KPUBLICTRANSPORT_MAKE_GADGET(JourneySection)
65 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, JourneySection::Mode, mode, setMode)
66 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, scheduledDepartureTime, setScheduledDepartureTime)
67 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, expectedDepartureTime, setExpectedDepartureTime)
68 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, scheduledArrivalTime, setScheduledArrivalTime)
69 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QDateTime, expectedArrivalTime, setExpectedArrivalTime)
70 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Location, from, setFrom)
71 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Location, to, setTo)
72 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Route, route, setRoute)
73 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Disruption::Effect, disruptionEffect, setDisruptionEffect)
74 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, QStringList, notes, setNotes)
75 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, RentalVehicle, rentalVehicle, setRentalVehicle)
76 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Path, path, setPath)
77 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Vehicle, departureVehicleLayout, setDepartureVehicleLayout)
78 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Platform, departurePlatformLayout, setDeparturePlatformLayout)
79 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Vehicle, arrivalVehicleLayout, setArrivalVehicleLayout)
80 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, Platform, arrivalPlatformLayout, setArrivalPlatformLayout)
81 KPUBLICTRANSPORT_MAKE_PROPERTY(JourneySection, KPublicTransport::IndividualTransport, individualTransport, setIndividualTransport)
82 
83 bool JourneySection::hasExpectedDepartureTime() const
84 {
85  return d->expectedDepartureTime.isValid();
86 }
87 
88 int JourneySection::departureDelay() const
89 {
90  if (hasExpectedDepartureTime()) {
91  return d->scheduledDepartureTime.secsTo(d->expectedDepartureTime) / 60;
92  }
93  return 0;
94 }
95 
96 bool JourneySection::hasExpectedArrivalTime() const
97 {
98  return d->expectedArrivalTime.isValid();
99 }
100 
101 int JourneySection::arrivalDelay() const
102 {
103  if (hasExpectedArrivalTime()) {
104  return d->scheduledArrivalTime.secsTo(d->expectedArrivalTime) / 60;
105  }
106  return 0;
107 }
108 
109 int JourneySection::duration() const
110 {
111  return d->scheduledDepartureTime.secsTo(d->scheduledArrivalTime);
112 }
113 
114 int JourneySection::distance() const
115 {
116  if (d->mode == JourneySection::Waiting) {
117  return 0;
118  }
119 
120  int dist = 0;
121  if (d->from.hasCoordinate() && d->to.hasCoordinate()) {
122  float startLat = d->from.latitude();
123  float startLon = d->from.longitude();
124 
125  for (const auto &stop : d->intermediateStops) {
126  if (!stop.stopPoint().hasCoordinate()) {
127  continue;
128  }
129  dist += Location::distance(startLat, startLon, stop.stopPoint().latitude(), stop.stopPoint().longitude());
130  startLat = stop.stopPoint().latitude();
131  startLon = stop.stopPoint().longitude();
132  }
133 
134  dist += Location::distance(startLat, startLon, d->to.latitude(), d->to.longitude());
135  }
136  dist = std::max(dist, d->path.distance());
137  return std::max(dist, d->distance);
138 }
139 
140 void JourneySection::setDistance(int value)
141 {
142  d.detach();
143  d->distance = value;
144 }
145 
147 {
148  return d->scheduledDeparturePlatform;
149 }
150 
151 void JourneySection::setScheduledDeparturePlatform(const QString &platform)
152 {
153  d.detach();
154  d->scheduledDeparturePlatform = PlatformUtils::normalizePlatform(platform);
155 }
156 
158 {
159  return d->expectedDeparturePlatform;
160 }
161 
162 void JourneySection::setExpectedDeparturePlatform(const QString &platform)
163 {
164  d.detach();
165  d->expectedDeparturePlatform = PlatformUtils::normalizePlatform(platform);
166 }
167 
168 bool JourneySection::hasExpectedDeparturePlatform() const
169 {
170  return !d->expectedDeparturePlatform.isEmpty();
171 }
172 
173 bool JourneySection::departurePlatformChanged() const
174 {
175  return PlatformUtils::platformChanged(d->scheduledDeparturePlatform, d->expectedDeparturePlatform);
176 }
177 
179 {
180  return d->scheduledArrivalPlatform;
181 }
182 
183 void JourneySection::setScheduledArrivalPlatform(const QString &platform)
184 {
185  d.detach();
186  d->scheduledArrivalPlatform = PlatformUtils::normalizePlatform(platform);
187 }
188 
190 {
191  return d->expectedArrivalPlatform;
192 }
193 
194 void JourneySection::setExpectedArrivalPlatform(const QString &platform)
195 {
196  d.detach();
197  d->expectedArrivalPlatform = PlatformUtils::normalizePlatform(platform);
198 }
199 
200 bool JourneySection::hasExpectedArrivalPlatform() const
201 {
202  return !d->expectedArrivalPlatform.isEmpty();
203 }
204 
205 bool JourneySection::arrivalPlatformChanged() const
206 {
207  return PlatformUtils::platformChanged(d->scheduledArrivalPlatform, d->expectedArrivalPlatform);
208 }
209 
211 {
212  const auto n = NotesUtil::normalizeNote(note);
213  const auto idx = NotesUtil::needsAdding(d->notes, n);
214  if (idx >= 0) {
215  d.detach();
216  NotesUtil::performAdd(d->notes, n, idx);
217  }
218 }
219 
220 void JourneySection::addNotes(const QStringList &notes)
221 {
222  for (const auto &n : notes) {
223  addNote(n);
224  }
225 }
226 
227 const std::vector<Stopover>& JourneySection::intermediateStops() const
228 {
229  return d->intermediateStops;
230 }
231 
232 std::vector<Stopover>&& JourneySection::takeIntermediateStops()
233 {
234  d.detach();
235  return std::move(d->intermediateStops);
236 }
237 
238 void JourneySection::setIntermediateStops(std::vector<Stopover> &&stops)
239 {
240  d.detach();
241  d->intermediateStops = std::move(stops);
242 }
243 
244 QVariantList JourneySection::intermediateStopsVariant() const
245 {
246  QVariantList l;
247  l.reserve(d->intermediateStops.size());
248  std::transform(d->intermediateStops.begin(), d->intermediateStops.end(), std::back_inserter(l), [](const auto &stop) { return QVariant::fromValue(stop); });
249  return l;
250 }
251 
253 {
254  Stopover dep;
255  dep.setStopPoint(from());
256  dep.setRoute(route());
257  dep.setScheduledDepartureTime(scheduledDepartureTime());
258  dep.setExpectedDepartureTime(expectedDepartureTime());
259  dep.setScheduledPlatform(scheduledDeparturePlatform());
260  dep.setExpectedPlatform(expectedDeparturePlatform());
261  dep.addNotes(notes());
262  dep.setDisruptionEffect(disruptionEffect());
263  dep.setVehicleLayout(departureVehicleLayout());
264  dep.setPlatformLayout(departurePlatformLayout());
265  return dep;
266 }
267 
269 {
270  Stopover arr;
271  arr.setStopPoint(to());
272  arr.setRoute(route());
273  arr.setScheduledArrivalTime(scheduledArrivalTime());
274  arr.setExpectedArrivalTime(expectedArrivalTime());
275  arr.setScheduledPlatform(scheduledArrivalPlatform());
276  arr.setExpectedPlatform(expectedArrivalPlatform());
277  arr.setDisruptionEffect(disruptionEffect());
278  arr.setVehicleLayout(arrivalVehicleLayout());
279  arr.setPlatformLayout(arrivalPlatformLayout());
280  return arr;
281 }
282 
283 int JourneySection::co2Emission() const
284 {
285  // TODO handle rental vehicles and ride sharing in here!
286  if (d->co2Emission >= 0) {
287  return d->co2Emission;
288  }
289 
290  struct {
291  Line::Mode mode;
292  int gramPerKm;
293  } static const emissionForModeMap[] = {
294  { Line::Air, 285 },
295  { Line::Boat, 245 },
296  { Line::Bus, 68 },
297  { Line::BusRapidTransit, 68 },
298  { Line::Coach, 68 },
299  { Line::Ferry, 245 },
300  { Line::LocalTrain, 14 },
301  { Line::LongDistanceTrain, 14 },
302  { Line::Metro, 11 },
303  { Line::RapidTransit, 11 },
304  { Line::Taxi, 158 },
305  { Line::Train, 14 },
306  { Line::Tramway, 11 },
307  };
308 
309  const auto mode = route().line().mode();
310  for (const auto &map : emissionForModeMap) {
311  if (map.mode == mode) {
312  return (map.gramPerKm * distance()) / 1000;
313  }
314  }
315  return -1;
316 }
317 
318 void JourneySection::setCo2Emission(int value)
319 {
320  d.detach();
321  d->co2Emission = value;
322 }
323 
324 const std::vector<LoadInfo>& JourneySection::loadInformation() const
325 {
326  return d->loadInformation;
327 }
328 
329 std::vector<LoadInfo>&& JourneySection::takeLoadInformation()
330 {
331  d.detach();
332  return std::move(d->loadInformation);
333 }
334 
335 void JourneySection::setLoadInformation(std::vector<LoadInfo> &&loadInfo)
336 {
337  d.detach();
338  d->loadInformation = std::move(loadInfo);
339 }
340 
341 QVariantList JourneySection::loadInformationVariant() const
342 {
343  QVariantList l;
344  l.reserve(d->loadInformation.size());
345  std::transform(d->loadInformation.begin(), d->loadInformation.end(), std::back_inserter(l), [](const auto &load) { return QVariant::fromValue(load); });
346  return l;
347 }
348 
349 bool JourneySection::isSame(const JourneySection &lhs, const JourneySection &rhs)
350 {
351  if (lhs.d->mode != rhs.d->mode) {
352  return false;
353  }
354 
356  return false;
357  }
358 
359  // we have N criteria to compare here, with 3 possible results:
360  // - equal
361  // - similar-ish, unknwon, or at least not conflicting
362  // - conflicting
363  // A single conflict results in a negative result, at least N - 1 equal comparisons lead to
364  // in a positive result.
365  enum { Equal = 1, Compatible = 0, Conflict = -1000 };
366  int result = 0;
367 
368  const auto depTimeDist = MergeUtil::distance(lhs.d->scheduledDepartureTime, rhs.d->scheduledDepartureTime);
369  result += depTimeDist < 60 ? Equal : depTimeDist <= 60 ? Compatible : Conflict;
370  const auto arrTimeDist = MergeUtil::distance(lhs.d->scheduledArrivalTime, rhs.d->scheduledArrivalTime);
371  result += arrTimeDist < 60 ? Equal : depTimeDist <= 60 ? Compatible : Conflict;
372 
373  const auto sameFrom = Location::isSame(lhs.d->from, rhs.d->from);
374  const auto fromDist = Location::distance(lhs.from(), rhs.from());
375  result += sameFrom ? Equal : fromDist < 200 ? Compatible : Conflict;
376 
377  const auto sameTo = Location::isSame(lhs.d->to, rhs.d->to);
378  const auto toDist = Location::distance(lhs.to(), rhs.to());
379  result += sameTo ? Equal : toDist < 200 ? Compatible : Conflict;
380 
381  const auto sameRoute = Route::isSame(lhs.d->route, rhs.d->route);
382  const auto sameDir = Location::isSameName(lhs.d->route.direction(), rhs.d->route.direction());
383  const auto sameLine = Line::isSame(lhs.d->route.line(), rhs.d->route.line());
384  result += sameRoute ? Equal : (sameDir || sameLine) ? Compatible : Conflict;
385 
387  result += lhs.scheduledDeparturePlatform() == rhs.scheduledDeparturePlatform() ? Equal : Conflict;
388  }
389 
390  return result >= 4;
391 }
392 
393 JourneySection JourneySection::merge(const JourneySection &lhs, const JourneySection &rhs)
394 {
395  using namespace MergeUtil;
396  auto res = lhs;
397  res.setScheduledDepartureTime(mergeDateTimeEqual(lhs.scheduledDepartureTime(), rhs.scheduledDepartureTime()));
398  res.setExpectedDepartureTime(mergeDateTimeMax(lhs.expectedDepartureTime(), rhs.expectedDepartureTime()));
399  res.setScheduledArrivalTime(mergeDateTimeMax(lhs.scheduledArrivalTime(), rhs.scheduledArrivalTime()));
400  res.setExpectedArrivalTime(mergeDateTimeMax(lhs.expectedArrivalTime(), rhs.expectedArrivalTime()));
401 
402  if (res.expectedDeparturePlatform().isEmpty()) {
403  res.setExpectedDeparturePlatform(rhs.expectedDeparturePlatform());
404  }
405  if (res.expectedArrivalPlatform().isEmpty()) {
406  res.setExpectedArrivalPlatform(rhs.expectedArrivalPlatform());
407  }
408  res.setFrom(Location::merge(lhs.from(), rhs.from()));
409  res.setTo(Location::merge(lhs.to(), rhs.to()));
410  res.setRoute(Route::merge(lhs.route(), rhs.route()));
411 
412  res.setScheduledDeparturePlatform(mergeString(lhs.scheduledDeparturePlatform(), rhs.scheduledDeparturePlatform()));
413  res.setScheduledArrivalPlatform(mergeString(lhs.scheduledArrivalPlatform(), rhs.scheduledArrivalPlatform()));
414 
415  res.setDisruptionEffect(std::max(lhs.disruptionEffect(), rhs.disruptionEffect()));
416  res.setNotes(NotesUtil::mergeNotes(lhs.notes(), rhs.notes()));
417  res.setDistance(std::max(lhs.distance(), rhs.distance()));
418 
419  if (lhs.intermediateStops().size() == rhs.intermediateStops().size()) {
420  auto stops = res.takeIntermediateStops();
421  for (uint i = 0; i < stops.size(); ++i) {
422  stops[i] = Stopover::merge(stops[i], rhs.intermediateStops()[i]);
423  stops[i].setRoute(res.route());
424  }
425  res.setIntermediateStops(std::move(stops));
426  }
427 
428  res.d->co2Emission = std::max(lhs.d->co2Emission, rhs.d->co2Emission);
429  res.d->loadInformation = LoadUtil::merge(lhs.d->loadInformation, rhs.d->loadInformation);
430  res.d->rentalVehicle = RentalVehicleUtil::merge(lhs.d->rentalVehicle, rhs.d->rentalVehicle);
431 
432  res.d->path = lhs.d->path.isEmpty() ? rhs.d->path : lhs.d->path;
433 
434  res.d->departureVehicleLayout = Vehicle::merge(lhs.d->departureVehicleLayout, rhs.d->departureVehicleLayout);
435  res.d->departurePlatformLayout = Platform::merge(lhs.d->departurePlatformLayout, rhs.d->departurePlatformLayout);
436  res.d->arrivalVehicleLayout = Vehicle::merge(lhs.d->arrivalVehicleLayout, rhs.d->arrivalVehicleLayout);
437  res.d->arrivalPlatformLayout = Platform::merge(lhs.d->arrivalPlatformLayout, rhs.d->arrivalPlatformLayout);
438 
439  return res;
440 }
441 
442 QJsonObject JourneySection::toJson(const JourneySection &section)
443 {
444  auto obj = Json::toJson(section);
445  if (section.mode() != Waiting) {
446  const auto fromObj = Location::toJson(section.from());
447  if (!fromObj.empty()) {
448  obj.insert(QLatin1String("from"), fromObj);
449  }
450  const auto toObj = Location::toJson(section.to());
451  if (!toObj.empty()) {
452  obj.insert(QLatin1String("to"), toObj);
453  }
454  }
455  if (section.mode() == PublicTransport) {
456  const auto routeObj = Route::toJson(section.route());
457  if (!routeObj.empty()) {
458  obj.insert(QLatin1String("route"), routeObj);
459  }
460  if (!section.intermediateStops().empty()) {
461  obj.insert(QLatin1String("intermediateStops"), Stopover::toJson(section.intermediateStops()));
462  }
463  if (!section.loadInformation().empty()) {
464  obj.insert(QLatin1String("load"), LoadInfo::toJson(section.loadInformation()));
465  }
466  }
467  if (section.d->co2Emission < 0) {
468  obj.remove(QLatin1String("co2Emission"));
469  }
470  if (section.rentalVehicle().type() != RentalVehicle::Unknown) {
471  obj.insert(QLatin1String("rentalVehicle"), RentalVehicle::toJson(section.rentalVehicle()));
472  }
473 
474  if (!section.path().isEmpty()) {
475  obj.insert(QLatin1String("path"), Path::toJson(section.path()));
476  }
477 
478  if (!section.departureVehicleLayout().isEmpty()) {
479  obj.insert(QLatin1String("departureVehicleLayout"), Vehicle::toJson(section.departureVehicleLayout()));
480  }
481  if (!section.departurePlatformLayout().isEmpty()) {
482  obj.insert(QLatin1String("departurePlatformLayout"), Platform::toJson(section.departurePlatformLayout()));
483  }
484  if (!section.arrivalVehicleLayout().isEmpty()) {
485  obj.insert(QLatin1String("arrivalVehicleLayout"), Vehicle::toJson(section.arrivalVehicleLayout()));
486  }
487  if (!section.arrivalPlatformLayout().isEmpty()) {
488  obj.insert(QLatin1String("arrivalPlatformLayout"), Platform::toJson(section.arrivalPlatformLayout()));
489  }
490 
491  if (section.mode() == JourneySection::IndividualTransport) {
492  obj.insert(QLatin1String("individualTransport"), IndividualTransport::toJson(section.individualTransport()));
493  }
494 
495  if (obj.size() <= 3) { // only the disruption and mode enums and distance, ie. this is an empty object
496  return {};
497  }
498  return obj;
499 }
500 
501 QJsonArray JourneySection::toJson(const std::vector<JourneySection> &sections)
502 {
503  return Json::toJson(sections);
504 }
505 
506 JourneySection JourneySection::fromJson(const QJsonObject &obj)
507 {
508  auto section = Json::fromJson<JourneySection>(obj);
509  section.setFrom(Location::fromJson(obj.value(QLatin1String("from")).toObject()));
510  section.setTo(Location::fromJson(obj.value(QLatin1String("to")).toObject()));
511  section.setRoute(Route::fromJson(obj.value(QLatin1String("route")).toObject()));
512  section.setIntermediateStops(Stopover::fromJson(obj.value(QLatin1String("intermediateStops")).toArray()));
513  section.setLoadInformation(LoadInfo::fromJson(obj.value(QLatin1String("load")).toArray()));
514  section.setRentalVehicle(RentalVehicle::fromJson(obj.value(QLatin1String("rentalVehicle")).toObject()));
515  section.setPath(Path::fromJson(obj.value(QLatin1String("path")).toObject()));
516  section.setDepartureVehicleLayout(Vehicle::fromJson(obj.value(QLatin1String("departureVehicleLayout")).toObject()));
517  section.setDeparturePlatformLayout(Platform::fromJson(obj.value(QLatin1String("departurePlatformLayout")).toObject()));
518  section.setArrivalVehicleLayout(Vehicle::fromJson(obj.value(QLatin1String("arrivalVehicleLayout")).toObject()));
519  section.setArrivalPlatformLayout(Platform::fromJson(obj.value(QLatin1String("arrivalPlatformLayout")).toObject()));
520  section.setIndividualTransport(IndividualTransport::fromJson(obj.value(QLatin1String("individualTransport")).toObject()));
521  return section;
522 }
523 
524 std::vector<JourneySection> JourneySection::fromJson(const QJsonArray &array)
525 {
526  return Json::fromJson<JourneySection>(array);
527 }
528 
529 
530 KPUBLICTRANSPORT_MAKE_GADGET(Journey)
531 
532 const std::vector<JourneySection>& Journey::sections() const
533 {
534  return d->sections;
535 }
536 
537 std::vector<JourneySection>&& Journey::takeSections()
538 {
539  d.detach();
540  return std::move(d->sections);
541 }
542 
543 void Journey::setSections(std::vector<JourneySection> &&sections)
544 {
545  d.detach();
546  d->sections = std::move(sections);
547 }
548 
549 QVariantList Journey::sectionsVariant() const
550 {
551  QVariantList l;
552  l.reserve(d->sections.size());
553  std::transform(d->sections.begin(), d->sections.end(), std::back_inserter(l), [](const auto &sec) { return QVariant::fromValue(sec); });
554  return l;
555 }
556 
557 QDateTime Journey::scheduledDepartureTime() const
558 {
559  if (!d->sections.empty()) {
560  return d->sections.front().scheduledDepartureTime();
561  }
562  return {};
563 }
564 
565 bool Journey::hasExpectedDepartureTime() const
566 {
567  return d->sections.empty() ? false : d->sections.front().hasExpectedDepartureTime();
568 }
569 
570 int Journey::departureDelay() const
571 {
572  return d->sections.empty() ? 0 : d->sections.front().departureDelay();
573 }
574 
575 QDateTime Journey::scheduledArrivalTime() const
576 {
577  if (!d->sections.empty()) {
578  return d->sections.back().scheduledArrivalTime();
579  }
580  return {};
581 }
582 
583 bool Journey::hasExpectedArrivalTime() const
584 {
585  return d->sections.empty() ? false : d->sections.back().hasExpectedArrivalTime();
586 }
587 
588 int Journey::arrivalDelay() const
589 {
590  return d->sections.empty() ? 0 : d->sections.back().arrivalDelay();
591 }
592 
593 int Journey::duration() const
594 {
595  return scheduledDepartureTime().secsTo(scheduledArrivalTime());
596 }
597 
598 int Journey::numberOfChanges() const
599 {
600  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));
601 }
602 
603 Disruption::Effect Journey::disruptionEffect() const
604 {
605  Disruption::Effect effect = Disruption::NormalService;
606  for (const auto &sec : d->sections) {
607  effect = std::max(effect, sec.disruptionEffect());
608  }
609  return effect;
610 }
611 
612 static bool isTransportSection(JourneySection::Mode mode)
613 {
614  return mode == JourneySection::PublicTransport
617 }
618 
619 bool Journey::isSame(const Journey &lhs, const Journey &rhs)
620 {
621  auto lIt = lhs.sections().begin();
622  auto rIt = rhs.sections().begin();
623 
624  while (lIt != lhs.sections().end() || rIt != rhs.sections().end()) {
625  // ignore non-transport sections
626  if (lIt != lhs.sections().end() && !isTransportSection((*lIt).mode())) {
627  ++lIt;
628  continue;
629  }
630  if (rIt != rhs.sections().end() && !isTransportSection((*rIt).mode())) {
631  ++rIt;
632  continue;
633  }
634 
635  if (lIt == lhs.sections().end() || rIt == rhs.sections().end()) {
636  return false;
637  }
638 
639  if (!JourneySection::isSame(*lIt, *rIt)) {
640  return false;
641  }
642 
643  ++lIt;
644  ++rIt;
645  }
646 
647  Q_ASSERT(lIt == lhs.sections().end() && rIt == rhs.sections().end());
648  return true;
649 }
650 
651 Journey Journey::merge(const Journey &lhs, const Journey &rhs)
652 {
653  std::vector<JourneySection> sections;
654  sections.reserve(lhs.sections().size() + rhs.sections().size());
655  std::copy(lhs.sections().begin(), lhs.sections().end(), std::back_inserter(sections));
656  std::copy(rhs.sections().begin(), rhs.sections().end(), std::back_inserter(sections));
657  std::sort(sections.begin(), sections.end(), [](const auto &lSec, const auto &rSec) {
658  if (MergeUtil::distance(lSec.scheduledDepartureTime(), rSec.scheduledDepartureTime()) == 0) {
659  return lSec.mode() < rSec.mode();
660  }
661  return MergeUtil::isBefore(lSec.scheduledDepartureTime(), rSec.scheduledDepartureTime());
662  });
663 
664  for (auto it = sections.begin(); it != sections.end(); ++it) {
665  const auto nextIt = it + 1;
666  if (nextIt == sections.end()) {
667  break;
668  }
669 
670  if (JourneySection::isSame(*it, *nextIt) || ((*it).mode() == (*nextIt).mode() && (*it).mode() != JourneySection::PublicTransport)) {
671  *it = JourneySection::merge(*it, *nextIt);
672  sections.erase(nextIt);
673  }
674  }
675 
676  Journey res;
677  res.setSections(std::move(sections));
678  return res;
679 }
680 
682 {
683  QJsonObject obj;
684  obj.insert(QStringLiteral("sections"), JourneySection::toJson(journey.sections()));
685  return obj;
686 }
687 
688 QJsonArray Journey::toJson(const std::vector<Journey> &journeys)
689 {
690  return Json::toJson(journeys);
691 }
692 
694 {
695  Journey j;
697  JourneyUtil::applyMetaData(j, false);
698  return j;
699 }
700 
701 std::vector<Journey> Journey::fromJson(const QJsonArray &array)
702 {
703  return Json::fromJson<Journey>(array);
704 }
705 
706 #include "moc_journey.cpp"
KPublicTransport::Vehicle departureVehicleLayout
Vehicle coach layout information at departure.
Definition: journey.h:144
QDateTime expectedArrivalTime
Actual arrival time, if available.
Definition: journey.h:71
KPublicTransport::IndividualTransport individualTransport
Individual transport details for sections using your own vehicle.
Definition: journey.h:156
VehicleType type
Vehicle type.
Definition: rentalvehicle.h:45
Query operations and data types for accessing realtime public transport information from online servi...
Definition: attribution.cpp:16
static Vehicle fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition: vehicle.cpp:218
const std::vector< Stopover > & intermediateStops() const
Intermediate stop-overs along this journey section.
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:619
static QJsonObject toJson(const Journey &journey)
Serializes one journey object to JSON.
Definition: journey.cpp:681
using your own vehicle (bike, car, etc).
Definition: journey.h:46
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:349
QVariantList sections
Journey sections for consumption by QML.
Definition: journey.h:233
static QJsonObject toJson(const JourneySection &section)
Serializes one journey section to JSON.
Definition: journey.cpp:442
Stopover departure() const
Returns the departure stopover of this journey section.
static QJsonObject toJson(const RentalVehicle &vehicle)
Serializes one object to JSON.
static Stopover fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition: stopover.cpp:241
QStringList notes
General human-readable notes on this service, e.g.
Definition: journey.h:110
static Path fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition: path.cpp:153
static RentalVehicle fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
free floating or dock-based rental bike service, electric scooters, car sharing services, ie. any vehicle you drive yourself but that isn&#39;t your own
Definition: journey.h:45
KPublicTransport::Platform departurePlatformLayout
Platform layout information at departure.
Definition: journey.h:146
Effect
Disruption effects, numerical sorted so that higher values imply more severe disruptions.
Definition: disruption.h:25
void setIntermediateStops(std::vector< Stopover > &&stops)
Set the intermediate stops.
Definition: journey.cpp:238
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:177
static QJsonObject toJson(const Route &r)
Serializes one object to JSON.
Definition: line.cpp:194
std::vector< Stopover > && takeIntermediateStops()
Moves the intermediate stops out of this object.
Definition: journey.cpp:232
QDateTime scheduledArrivalTime
Planned arrival time.
Definition: journey.h:67
QDateTime expectedDepartureTime
Actual departure time, if available.
Definition: journey.h:60
Individual transport mode details for a journey section, and for specifying journey requests...
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:262
KPublicTransport::Disruption::Effect disruptionEffect
Disruption effect on this section, if any.
Definition: journey.h:108
static QJsonObject toJson(const Stopover &stopover)
Serializes one object to JSON.
Definition: stopover.cpp:209
static Journey merge(const Journey &lhs, const Journey &rhs)
Merge two instances.
Definition: journey.cpp:651
void addNote(const QString &note)
Adds a note.
Definition: journey.cpp:210
void setSections(std::vector< JourneySection > &&sections)
Sets the journey sections.
Definition: journey.cpp:543
A segment of a journey plan.
Definition: journey.h:31
A route of a public transport line.
Definition: line.h:120
Mode
Mode of transport.
Definition: journey.h:39
QString scheduledArrivalPlatform
Planned arrival platform.
Definition: journey.h:99
static Journey fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition: journey.cpp:693
bool isEmpty() const
Returns true if this object contains no information beyond the default values.
Definition: vehicle.cpp:118
const std::vector< JourneySection > & sections() const
The journey sections.
Mode
Mode of transportation.
Definition: line.h:31
static bool isSameName(const QString &lhs, const QString &rhs)
Checks if two location names refer to the same location.
Definition: location.cpp:321
Stopover arrival() const
Returns the arrival stopover of this journey section.
KGuiItem stop()
static JourneySection fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition: journey.cpp:506
static Location fromJson(const QJsonObject &obj)
Deserialize a Location object from JSON.
Definition: location.cpp:485
QJsonObject toObject() const const
QJsonArray toArray() const const
QDateTime scheduledDepartureTime
Planned departure time.
Definition: journey.h:56
bool isEmpty() const const
Information about the vehicle used on a journey.
Definition: vehicle.h:140
static Location merge(const Location &lhs, const Location &rhs)
Merge two departure instances.
Definition: location.cpp:368
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:95
void setLoadInformation(std::vector< LoadInfo > &&loadInfo)
Set the vehicle load information for this journey section.
Definition: journey.cpp:335
static Route merge(const Route &lhs, const Route &rhs)
Merge two Route instances.
Definition: line.cpp:185
static LoadInfo fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition: load.cpp:36
static Platform fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition: platform.cpp:113
KPublicTransport::RentalVehicle rentalVehicle
Information about a rental vehicle, for sections using one.
Definition: journey.h:135
Mode mode
Mode of transport for this section.
Definition: journey.h:53
int distance(const GeoCoordinates &coord1, const GeoCoordinates &coord2)
KPublicTransport::Platform arrivalPlatformLayout
Platform layout information at arrival.
Definition: journey.h:153
static QJsonObject toJson(const Platform &platform)
Serializes one platform object to JSON.
Definition: platform.cpp:99
static Vehicle merge(const Vehicle &lhs, const Vehicle &rhs)
Merge two Vehicle instances.
Definition: vehicle.cpp:182
QString expectedArrivalPlatform
Actual arrival platform, in case real-time information are available.
Definition: journey.h:101
static Route fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
Definition: line.cpp:207
bool isEmpty() const
Returns true if this is an empty/not-set path.
Definition: path.cpp:109
KPublicTransport::Vehicle arrivalVehicleLayout
Vehicle coach layout information at arrival.
Definition: journey.h:151
std::vector< JourneySection > && takeSections()
Moves the journey sections out of this object.
Definition: journey.cpp:537
QVariant fromValue(const T &value)
A journey plan.
Definition: journey.h:229
Information about an arrival and/or departure of a vehicle at a stop area.
Definition: stopover.h:25
KPublicTransport::Location to
Arrival location of this segment.
Definition: journey.h:85
static QJsonObject toJson(const Vehicle &vehicle)
Serializes one vehicle object to JSON.
Definition: vehicle.cpp:204
KPublicTransport::Route route
Route to take on this segment.
Definition: journey.h:87
static QJsonObject toJson(const IndividualTransport &it)
Serializes one object to JSON.
static IndividualTransport fromJson(const QJsonObject &obj)
Deserialize an object from JSON.
static QJsonObject toJson(const Location &loc)
Serializes one Location object to JSON.
Definition: location.cpp:444
Information about the layout of a station platform.
Definition: platform.h:44
A path followed by any kind of location change.
Definition: path.h:88
QString scheduledDeparturePlatform
Planned departure platform.
Definition: journey.h:90
std::vector< LoadInfo > && takeLoadInformation()
Moves the load information out of this object for modification.
Definition: journey.cpp:329
int co2Emission
CO₂ emission during this journey section, in gram.
Definition: journey.h:127
QJsonValue value(const QString &key) const const
KPublicTransport::Path path
Movement path for this journey section.
Definition: journey.h:141
static float distance(float lat1, float lon1, float lat2, float lon2)
Compute the distance between two geo coordinates, in meters.
Definition: location.cpp:424
KPublicTransport::Line line
Line this route belongs to.
Definition: line.h:124
QVariantList intermediateStops
Intermediate stops for consumption by QML.
Definition: journey.h:113
int distance
Distance of the section in meter.
Definition: journey.h:80
const std::vector< LoadInfo > & loadInformation() const
Vehicle load information for this journey section, if available.
static Platform merge(const Platform &lhs, const Platform &rhs)
Merge two platform instances.
Definition: platform.cpp:93
QString expectedDeparturePlatform
Actual departure platform, in case real-time information are available.
Definition: journey.h:92
static JourneySection merge(const JourneySection &lhs, const JourneySection &rhs)
Merge two instances.
Definition: journey.cpp:393
An individual rental vehicle used on a JourneySection, ie.
Definition: rentalvehicle.h:27
static QJsonObject toJson(const LoadInfo &info)
Serializes one load information object to JSON.
Definition: load.cpp:26
static Stopover merge(const Stopover &lhs, const Stopover &rhs)
Merge two departure instances.
Definition: stopover.cpp:182
QJsonObject::iterator insert(const QString &key, const QJsonValue &value)
static QJsonObject toJson(const Path &path)
Serializes one path object to JSON.
Definition: path.cpp:146
QVariantList loadInformation
Vehicle load information for this journey section.
Definition: journey.h:132
bool isEmpty() const
Returns true if this object contains no information beyond default values.
Definition: platform.cpp:66
KPublicTransport::Location from
Departure location of this segment.
Definition: journey.h:83
QString direction
Direction of the route.
Definition: line.h:130
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Oct 24 2021 23:05:21 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.