File indexing completed on 2024-05-12 04:42:45

0001 /*
0002     SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "path.h"
0008 #include "datatypes_p.h"
0009 #include "json_p.h"
0010 #include "../geo/geojson_p.h"
0011 #include "location.h"
0012 
0013 #include <QLineF>
0014 
0015 using namespace KPublicTransport;
0016 
0017 namespace KPublicTransport {
0018 class PathSectionPrivate : public QSharedData {
0019 public:
0020     QPolygonF path;
0021     QString description;
0022     int floorLevelChange = 0;
0023     PathSection::Maneuver maneuver = PathSection::Move;
0024 };
0025 }
0026 
0027 KPUBLICTRANSPORT_MAKE_GADGET(PathSection)
0028 KPUBLICTRANSPORT_MAKE_PROPERTY(PathSection, QPolygonF, path, setPath)
0029 KPUBLICTRANSPORT_MAKE_PROPERTY(PathSection, QString, description, setDescription)
0030 KPUBLICTRANSPORT_MAKE_PROPERTY(PathSection, int, floorLevelChange, setFloorLevelChange)
0031 KPUBLICTRANSPORT_MAKE_PROPERTY(PathSection, PathSection::Maneuver, maneuver, setManeuver)
0032 
0033 int PathSection::distance() const
0034 {
0035     if (d->path.size() < 2) {
0036         return 0;
0037     }
0038 
0039     float dist = 0;
0040     for (auto it = d->path.begin(); it != std::prev(d->path.end()); ++it) {
0041         const auto nextIt = std::next(it);
0042         dist += Location::distance((*it).y(), (*it).x(), (*nextIt).y(), (*nextIt).x());
0043     }
0044     return dist;
0045 }
0046 
0047 int PathSection::direction() const
0048 {
0049     const auto p1 = startPoint();
0050     const auto p2 = endPoint();
0051     if (d->path.size() < 2 || p1 == p2) {
0052         return -1;
0053     }
0054     return static_cast<int>(450 - QLineF(p1.x(), -p1.y(), p2.x(), -p2.y()).angle()) % 360;
0055 }
0056 
0057 QPointF PathSection::startPoint() const
0058 {
0059     return d->path.empty() ? QPointF() : d->path.constFirst();
0060 }
0061 
0062 QPointF PathSection::endPoint() const
0063 {
0064     return d->path.empty() ? QPointF() : d->path.constLast();
0065 }
0066 
0067 QJsonObject PathSection::toJson(const PathSection &section)
0068 {
0069     auto obj = Json::toJson(section);
0070     if (!section.path().empty()) {
0071         obj.insert(QLatin1String("path"), GeoJson::writeLineString(section.path()));
0072     }
0073     if (section.maneuver() == PathSection::Move) {
0074         obj.remove(QLatin1String("maneuver"));
0075     }
0076     if (section.floorLevelChange() == 0) {
0077         obj.remove(QLatin1String("floorLevelChange"));
0078     }
0079     return obj;
0080 }
0081 
0082 QJsonArray PathSection::toJson(const std::vector<PathSection> &sections)
0083 {
0084     return Json::toJson(sections);
0085 }
0086 
0087 PathSection PathSection::fromJson(const QJsonObject &obj)
0088 {
0089     auto section = Json::fromJson<PathSection>(obj);
0090     section.setPath(GeoJson::readLineString(obj.value(QLatin1String("path")).toObject()));
0091     return section;
0092 }
0093 
0094 std::vector<PathSection> PathSection::fromJson(const QJsonArray &array)
0095 {
0096     return Json::fromJson<PathSection>(array);
0097 }
0098 
0099 
0100 namespace KPublicTransport {
0101 class PathPrivate : public QSharedData {
0102 public:
0103     std::vector<PathSection> sections;
0104 };
0105 }
0106 
0107 KPUBLICTRANSPORT_MAKE_GADGET(Path)
0108 
0109 bool Path::isEmpty() const
0110 {
0111     return d->sections.empty();
0112 }
0113 
0114 const std::vector<PathSection>& Path::sections() const
0115 {
0116     return d->sections;
0117 }
0118 
0119 std::vector<PathSection>&& Path::takeSections()
0120 {
0121     d.detach();
0122     return std::move(d->sections);
0123 }
0124 
0125 void Path::setSections(std::vector<PathSection> &&sections)
0126 {
0127     d.detach();
0128     d->sections = std::move(sections);
0129 }
0130 
0131 int Path::distance() const
0132 {
0133     return std::accumulate(d->sections.begin(), d->sections.end(), 0, [](int d, const auto &sec) { return d + sec.distance(); });
0134 }
0135 
0136 QPointF Path::startPoint() const
0137 {
0138     return isEmpty() ? QPointF() : d->sections.front().startPoint();
0139 }
0140 
0141 QPointF Path::endPoint() const
0142 {
0143     return isEmpty() ? QPointF() : d->sections.front().endPoint();
0144 }
0145 
0146 QJsonObject Path::toJson(const Path &path)
0147 {
0148     auto obj = Json::toJson(path);
0149     obj.insert(QLatin1String("sections"), PathSection::toJson(path.sections()));
0150     return obj;
0151 }
0152 
0153 Path Path::fromJson(const QJsonObject &obj)
0154 {
0155     auto path = Json::fromJson<Path>(obj);
0156     path.setSections(PathSection::fromJson(obj.value(QLatin1String("sections")).toArray()));
0157     return path;
0158 }
0159 
0160 int Path::sectionCount() const
0161 {
0162     return d->sections.size();
0163 }
0164 
0165 #include "moc_path.cpp"