KPublicTransport

tripreply.cpp
1/*
2 SPDX-FileCopyrightText: 2025 Volker Krause <vkrause@kde.org>
3 SPDX-License-Identifier: LGPL-2.0-or-later
4*/
5
6#include "tripreply.h"
7
8#include "logging.h"
9#include "reply_p.h"
10#include "triprequest.h"
11
12#include "backends/abstractbackend.h"
13#include "backends/cache.h"
14#include "datatypes/journeyutil_p.h"
15
16#include <KPublicTransport/Journey>
17#include <KPublicTransport/Stopover>
18
19namespace KPublicTransport {
20class TripReplyPrivate: public ReplyPrivate {
21public:
22 void finalizeResult() override {}
23
24 TripRequest request;
25 JourneySection trip;
26};
27}
28
29using namespace KPublicTransport;
30
31TripReply::TripReply(const TripRequest &req, QObject *parent)
32 : Reply(new TripReplyPrivate, parent)
33{
35 d->request = req;
36 d->trip = req.journeySection();
37}
38
39TripReply::~TripReply() = default;
40
42{
43 Q_D(const TripReply);
44 return d->request;
45}
46
47JourneySection TripReply::trip() const
48{
49 Q_D(const TripReply);
50 return d->trip;
51}
52
54{
55 Q_D(const TripReply);
56 auto partialTrip = d->request.journeySection();
57
58 // do we have enough to go on to cut out a partial trip? is that even needed?
59 if (partialTrip.from().name().isEmpty() || partialTrip.to().name().isEmpty() || JourneySection::isSame(partialTrip, d->trip) || d->trip.intermediateStops().empty()) {
60 return d->trip;
61 }
62
63 const auto &stopovers = d->trip.intermediateStops();
64 auto it = stopovers.begin();
65 if (!Stopover::isSame(partialTrip.departure(), d->trip.departure())) {
66 for (; it != stopovers.end(); ++it) {
67 if (Stopover::isSame(partialTrip.departure(), *it)) {
68 partialTrip.setDeparture(*it);
69 break;
70 }
71 }
72 if (it == stopovers.end()) {
73 return d->trip;
74 }
75 ++it;
76 }
77
78 auto it2 = it;
79 for (; it2 != stopovers.end(); ++it2) {
80 if (Stopover::isSame(partialTrip.arrival(), *it2)) {
81 partialTrip.setArrival(*it2);
82 break;
83 }
84 }
85 if (it2 == stopovers.end() && !Stopover::isSame(partialTrip.arrival(), d->trip.arrival())) {
86 return d->trip;
87 }
88
89 partialTrip.setIntermediateStops({it, it2});
90 partialTrip.setRoute(d->trip.route());
91
92 auto path = d->trip.path();
93 auto pathSections = path.takeSections();
94
95 // find the closest points on the path to the departure/arrival locations
96 // we have to expect aribitrarly broken/imprecise data here...
97 qsizetype beginSection = -1, beginPoint = -1, endSection = -1, endPoint = -1;
98 double beginMinDist = std::numeric_limits<double>::max(), endMinDist = std::numeric_limits<double>::max();
99 for (std::size_t i = 0; i < pathSections.size(); ++i) {
100 const auto poly = pathSections[i].path();
101 for (qsizetype j = 0; j < poly.size(); ++j) {
102 const auto p = poly[j];
103 if (const auto d = Location::distance(p.y(), p.x(), partialTrip.from().latitude(), partialTrip.from().longitude()); d <beginMinDist) {
104 beginSection = (qsizetype)i;
105 beginPoint = j;
106 beginMinDist = d;
107 }
108 if (const auto d = Location::distance(p.y(), p.x(), partialTrip.to().latitude(), partialTrip.to().longitude()); d <endMinDist) {
109 endSection = (qsizetype)i;
110 endPoint = j;
111 endMinDist = d;
112 }
113 }
114 }
115
116 // if we found something, truncate path accordingly
117 if (std::tie(beginSection, beginPoint) < std::tie(endSection, endPoint)) {
118 // start cutting from the end, as otherwise the end indices become invalid!
119 pathSections.erase(pathSections.begin() + endSection + 1, pathSections.end());
120 pathSections.erase(pathSections.begin(), pathSections.begin() + beginSection);
121
122 auto poly = pathSections.back().path();
123 poly.erase(poly.begin() + endPoint + 1, poly.end());
124 pathSections.back().setPath(poly);
125
126 poly = pathSections.front().path();
127 poly.erase(poly.begin(), poly.begin() + beginPoint);
128 pathSections.front().setPath(poly);
129
130 path.setSections(std::move(pathSections));
131 partialTrip.setPath(path);
132 }
133
134 return partialTrip;
135}
136
137void TripReply::addResult(const AbstractBackend *backend, JourneySection &&journeySection)
138{
139 Q_D(TripReply);
140 JourneyUtil::propagateTimeZones(journeySection);
141
143 d->trip = JourneySection::merge(d->trip, journeySection);
144 } else {
145 auto route = Route::merge(d->trip.route(), journeySection.route());
146 d->trip = journeySection;
147 d->trip.setRoute(route);
148 }
149
150 JourneyUtil::postProcessPath(d->trip);
151 d->trip.applyMetaData(request().downloadAssets());
152
153 // apply static attributions if @p backend contributed to the results (can be nullptr for emulated results!)
154 if (backend) {
155 addAttribution(backend->attribution());
156 }
157
158 d->pendingOps--;
159 d->emitFinishedIfDone(this);
160}
161
162void TripReply::addError(const AbstractBackend *backend, Reply::Error error, const QString &errorMsg)
163{
164 if (error == Reply::NotFoundError) {
165 // TODO add negative cache entry
166 } else {
167 qCDebug(Log) << backend->backendId() << error << errorMsg;
168 }
169 Reply::addError(error, errorMsg);
170}
171
172#include "moc_tripreply.cpp"
A segment of a journey plan.
Definition journey.h:32
static JourneySection merge(const JourneySection &lhs, const JourneySection &rhs)
Merge two instances.
Definition journey.cpp:623
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:573
KPublicTransport::Route route
Route to take on this segment.
Definition journey.h:87
static double distance(double lat1, double lon1, double lat2, double lon2)
Compute the distance between two geo coordinates, in meters.
Definition location.cpp:458
Query response base class.
Definition reply.h:25
Error
Error types.
Definition reply.h:33
@ NotFoundError
The requested journey/departure/place could not be found.
Definition reply.h:36
static Route merge(const Route &lhs, const Route &rhs)
Merge two Route instances.
Definition line.cpp:276
static bool isSame(const Stopover &lhs, const Stopover &rhs)
Checks if to instances refer to the same departure (which does not necessarily mean they are exactly ...
Definition stopover.cpp:182
Reply to a trip query.
Definition tripreply.h:23
JourneySection journeySection() const
The sub-trip matching the JourneySection used in the request.
Definition tripreply.cpp:53
TripRequest request() const
The request this is the reply for.
Definition tripreply.cpp:41
Request for a single trip.
Definition triprequest.h:29
KPublicTransport::JourneySection journeySection
A JourneySection for which the full trip is requested.
Definition triprequest.h:32
Query operations and data types for accessing realtime public transport information from online servi...
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 31 2025 11:52:18 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.