7#include "journeyreply.h"
9#include "journeyrequest.h"
10#include "requestcontext_p.h"
12#include "backends/abstractbackend.h"
13#include "backends/cache.h"
14#include "datatypes/journeyutil_p.h"
16#include <KPublicTransport/Journey>
17#include <KPublicTransport/Location>
25class JourneyReplyPrivate :
public ReplyPrivate {
27 void finalizeResult()
override;
28 bool needToWaitForAssets()
const override;
29 static void postProcessJourneys(std::vector<Journey> &journeys);
34 std::vector<Journey> journeys;
38void JourneyReplyPrivate::finalizeResult()
40 if (journeys.empty()) {
48 std::sort(journeys.begin(), journeys.end(), JourneyUtil::firstTransportDepartureLessThan);
49 for (
auto it = journeys.begin(); it != journeys.end(); ++it) {
50 for (
auto mergeIt = it + 1; mergeIt != journeys.end();) {
51 if (!JourneyUtil::firstTransportDepartureEqual(*it, *mergeIt)) {
57 mergeIt = journeys.erase(mergeIt);
65 std::sort(journeys.begin(), journeys.end(), [](
const auto &lhs,
const auto &rhs) {
66 return lhs.scheduledDepartureTime() < rhs.scheduledDepartureTime();
69 nextRequest.purgeLoops(request);
70 prevRequest.purgeLoops(request);
73bool JourneyReplyPrivate::needToWaitForAssets()
const
80 if (section.
mode() == JourneySection::Waiting) {
83 if (section.
mode() == JourneySection::Walking) {
91 if ((section.
mode() == JourneySection::Transfer || section.
mode() == JourneySection::Walking)
92 && section.
from().hasCoordinate() && section.
to().hasCoordinate())
96 qCDebug(
Log) <<
"discarding journey based on insane transfer/walking speed:" << (
distance / section.
duration()) <<
"m/s";
99 if (distance > 100000) {
100 qCDebug(
Log) <<
"discarding journey with insane transfer/walking distance:" <<
distance <<
"m" << section.
from().
name() << section.
to().
name();
107void JourneyReplyPrivate::postProcessJourneys(std::vector<Journey> &journeys)
110 for (
auto &journey : journeys) {
111 auto sections = journey.takeSections();
112 for (
auto §ion : sections) {
113 if (section.
mode() == JourneySection::Walking) {
115 auto from = section.
from();
117 section.setFrom(from);
120 section.setScheduledDepartureTime(dt);
123 auto to = section.
to();
128 section.setScheduledArrivalTime(dt);
132 journey.setSections(std::move(sections));
136 for (
auto &journey : journeys) {
137 auto sections = journey.takeSections();
140 for (
auto it = sections.begin(); it != sections.end();) {
141 if (it == sections.begin()) {
145 auto prevIt = it - 1;
146 if ((*it).mode() == JourneySection::Walking && (*prevIt).mode() == JourneySection::Walking) {
147 (*prevIt).setTo((*it).to());
148 (*prevIt).setScheduledArrivalTime((*it).scheduledArrivalTime());
149 (*prevIt).setExpectedArrivalTime((*it).expectedArrivalTime());
150 (*prevIt).setDistance((*prevIt).distance() + (*it).distance());
151 it = sections.erase(it);
159 sections.erase(std::remove_if(sections.begin(), sections.end(), isPointlessSection), sections.end());
162 for (
auto §ion : sections) {
163 if (!section.
from().hasCoordinate() || !section.
to().hasCoordinate() || section.
path().
isEmpty()) {
169 if (pathDist > pointDist * 10) {
170 qCDebug(
Log) <<
"Dropping implausibly long path:" << pointDist << pathDist;
175 journey.setSections(std::move(sections));
179 journeys.erase(std::remove_if(journeys.begin(), journeys.end(), [](
const auto &journey) {
180 return journey.sections().empty() || std::any_of(journey.sections().begin(), journey.sections().end(), isImplausibleSection);
185 :
Reply(new JourneyReplyPrivate, parent)
189 d->nextRequest = req;
190 d->prevRequest = req;
193JourneyReply::~JourneyReply() =
default;
210 return std::move(d->journeys);
216 if (d->nextRequest.contexts().empty()) {
219 return d->nextRequest;
225 if (d->prevRequest.contexts().empty()) {
228 return d->prevRequest;
231void JourneyReply::addResult(
const AbstractBackend *backend, std::vector<Journey> &&res)
234 d->postProcessJourneys(res);
240 auto context = d->nextRequest.context(backend);
241 context.type = RequestContext::Next;
242 for (
const auto &jny : res) {
243 context.dateTime = std::max(context.dateTime, jny.scheduledDepartureTime());
245 d->nextRequest.setContext(backend, std::move(context));
247 context = d->prevRequest.context(backend);
248 context.type = RequestContext::Previous;
249 context.dateTime = res[0].scheduledArrivalTime();
250 for (
const auto &jny : res) {
251 context.dateTime = std::min(context.dateTime, jny.scheduledArrivalTime());
253 d->prevRequest.setContext(backend, std::move(context));
257 if (backend->timeZone().isValid()) {
258 for (
auto &jny : res) {
259 JourneyUtil::applyTimeZone(jny, backend->timeZone());
264 for (
auto &jny : res) {
265 jny.applyMetaData(
request().downloadAssets());
270 Cache::addNegativeJourneyCacheEntry(backend->backendId(),
request().cacheKey());
274 addAttribution(backend->attribution());
278 if (d->journeys.empty()) {
279 d->journeys = std::move(res);
281 d->journeys.insert(d->journeys.end(), res.begin(), res.end());
283 d->emitUpdated(
this);
287 d->emitFinishedIfDone(
this);
290void JourneyReply::setNextContext(
const AbstractBackend *backend,
const QVariant &data)
293 auto context = d->nextRequest.context(backend);
294 context.type = RequestContext::Next;
295 context.backendData = data;
296 d->nextRequest.setContext(backend, std::move(context));
299void JourneyReply::setPreviousContext(
const AbstractBackend *backend,
const QVariant &data)
302 auto context = d->prevRequest.context(backend);
303 context.type = RequestContext::Previous;
304 context.backendData = data;
305 d->prevRequest.setContext(backend, std::move(context));
308void JourneyReply::addError(
const AbstractBackend *backend,
Reply::Error error,
const QString &errorMsg)
311 Cache::addNegativeJourneyCacheEntry(backend->backendId(),
request().cacheKey());
313 qCDebug(
Log) << backend->backendId() <<
error << errorMsg;
315 Reply::addError(
error, errorMsg);
const std::vector< Journey > & result() const
Returns the retrieved journeys.
JourneyRequest nextRequest() const
Returns a request object for querying journeys following the ones returned by this reply.
std::vector< Journey > && takeResult()
Returns the retrieved journeys for moving elsewhere.
JourneyRequest previousRequest() const
Returns a request object for querying journeys preceding the ones returned by this reply.
JourneyRequest request() const
The request this is the reply for.
Describes a journey search.
bool downloadAssets
Download graphic assets such as line logos for the data requested here.
@ Departure
dateTime() represents the desired departure time.
A segment of a journey plan.
KPublicTransport::Path path
Movement path for this journey section.
KPublicTransport::Location from
Departure location of this segment.
QDateTime scheduledDepartureTime
Planned departure time.
KPublicTransport::Location to
Arrival location of this segment.
int duration
Duration of the section in seconds.
Mode mode
Mode of transport for this section.
QDateTime scheduledArrivalTime
Planned arrival time.
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...
static Journey merge(const Journey &lhs, const Journey &rhs)
Merge two instances.
QTimeZone timeZone() const
The timezone this location is in, if known.
static float distance(float lat1, float lon1, float lat2, float lon2)
Compute the distance between two geo coordinates, in meters.
QString name
Human-readable name of the location.
int distance
The length of this path in meters.
bool isEmpty() const
Returns true if this is an empty/not-set path.
Query response base class.
Error error() const
Error code.
@ NoError
Nothing went wrong.
@ NotFoundError
The requested journey/departure/place could not be found.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
Query operations and data types for accessing realtime public transport information from online servi...
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
void setTimeZone(const QTimeZone &toZone)
bool isValid() const const