From 4489fff0022430131ebfc6dc0499e9cdf0464aff Mon Sep 17 00:00:00 2001 From: Volker Krause Date: Sat, 5 Jan 2019 16:45:02 +0100 Subject: [PATCH] Merge journey results from multiple sources --- src/publictransport/datatypes/journey.cpp | 59 +++++++++++++++++++++++ src/publictransport/datatypes/journey.h | 17 +++++++ src/publictransport/journeyreply.cpp | 19 ++++++++ 3 files changed, 95 insertions(+) diff --git a/src/publictransport/datatypes/journey.cpp b/src/publictransport/datatypes/journey.cpp index de0a27b..75b48ec 100644 --- a/src/publictransport/datatypes/journey.cpp +++ b/src/publictransport/datatypes/journey.cpp @@ -234,6 +234,39 @@ bool JourneySection::arrivalPlatformChanged() const return hasExpectedArrivalPlatform() && d->scheduledArrivalPlatform != d->expectedArrivalPlatform; } +bool JourneySection::isSame(const JourneySection &lhs, const JourneySection &rhs) +{ + return lhs.d->mode == rhs.d->mode + && lhs.d->scheduledDepartureTime == rhs.d->scheduledDepartureTime + && lhs.d->scheduledArrivalTime == rhs.d->scheduledArrivalTime + && Location::isSame(lhs.d->from, rhs.d->from) + && Location::isSame(lhs.d->to, rhs.d->to) + && Route::isSame(lhs.d->route, rhs.d->route); + // ### platforms relevant? +} + +JourneySection JourneySection::merge(const JourneySection &lhs, const JourneySection &rhs) +{ + auto res = lhs; + if (!res.expectedDepartureTime().isValid()) { + res.setExpectedDepartureTime(rhs.expectedDepartureTime()); + } + if (res.expectedDeparturePlatform().isEmpty()) { + res.setExpectedDeparturePlatform(rhs.expectedDeparturePlatform()); + } + if (!res.expectedArrivalTime().isValid()) { + res.setExpectedArrivalTime(rhs.expectedArrivalTime()); + } + if (res.expectedArrivalPlatform().isEmpty()) { + res.setExpectedArrivalPlatform(rhs.expectedArrivalPlatform()); + } + res.setFrom(Location::merge(lhs.from(), rhs.from())); + res.setTo(Location::merge(lhs.to(), rhs.to())); + res.setRoute(Route::merge(lhs.route(), rhs.route())); + + return res; +} + KPUBLICTRANSPORT_MAKE_GADGET(Journey) @@ -287,4 +320,30 @@ int Journey::numberOfChanges() const return std::count_if(d->sections.begin(), d->sections.end(), [](const auto §ion) { return section.mode() == JourneySection::PublicTransport; }); } +bool Journey::isSame(const Journey &lhs, const Journey &rhs) +{ + // ### we can make this more clever by ignoring transit elements for example + // doing that will need changes below too! + if (lhs.sections().size() != rhs.sections().size()) { + return false; + } + return std::equal(lhs.sections().begin(), lhs.sections().end(), rhs.sections().begin(), [](const auto &lhs, const auto &rhs) { + return JourneySection::isSame(lhs, rhs); + }); +} + +Journey Journey::merge(const Journey &lhs, const Journey &rhs) +{ + // ### see above + std::vector sections; + sections.reserve(lhs.sections().size()); + for (auto lit = lhs.sections().begin(), rit = rhs.sections().begin(); lit != lhs.sections().end(); ++lit, ++rit) { + sections.push_back(JourneySection::merge(*lit, *rit)); + } + + Journey res; + res.setSections(std::move(sections)); + return res; +} + #include "moc_journey.cpp" diff --git a/src/publictransport/datatypes/journey.h b/src/publictransport/datatypes/journey.h index 9706f79..c7560ae 100644 --- a/src/publictransport/datatypes/journey.h +++ b/src/publictransport/datatypes/journey.h @@ -136,6 +136,14 @@ public: void setExpectedArrivalPlatform(const QString &platform); bool hasExpectedArrivalPlatform() const; bool arrivalPlatformChanged() const; + + /** Checks if two instances refer to the same journey section (which does not necessarily mean they are exactly equal). */ + static bool isSame(const JourneySection &lhs, const JourneySection &rhs); + + /** Merge two instances. + * This assumes isSame(lhs, rhs) and tries to preserve the most detailed information. + */ + static JourneySection merge(const JourneySection &lhs, const JourneySection &rhs); }; class JourneyPrivate; @@ -167,6 +175,15 @@ public: QDateTime scheduledArrivalTime() const; int duration() const; int numberOfChanges() const; + + /** Checks if two instances refer to the same journey (which does not necessarily mean they are exactly equal). */ + static bool isSame(const Journey &lhs, const Journey &rhs); + + /** Merge two instances. + * This assumes isSame(lhs, rhs) and tries to preserve the most detailed information. + */ + static Journey merge(const Journey &lhs, const Journey &rhs); + private: QVariantList sectionsVariant() const; }; diff --git a/src/publictransport/journeyreply.cpp b/src/publictransport/journeyreply.cpp index 5ceadac..377c2fc 100644 --- a/src/publictransport/journeyreply.cpp +++ b/src/publictransport/journeyreply.cpp @@ -81,6 +81,25 @@ void JourneyReplyPrivate::postProcessJourneys() } journey.setSections(std::move(sections)); } + + // sort and merge results + std::sort(journeys.begin(), journeys.end(), [](const auto &lhs, const auto &rhs) { + return lhs.scheduledDepartureTime() < rhs.scheduledDepartureTime(); + }); + for (auto it = journeys.begin(); it != journeys.end(); ++it) { + for (auto mergeIt = it + 1; mergeIt != journeys.end();) { + if ((*it).scheduledDepartureTime() != (*mergeIt).scheduledDepartureTime()) { + break; + } + + if (Journey::isSame(*it, *mergeIt)) { + *it = Journey::merge(*it, *mergeIt); + mergeIt = journeys.erase(mergeIt); + } else { + ++mergeIt; + } + } + } } JourneyReply::JourneyReply(const JourneyRequest &req) -- GitLab