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

0001 /*
0002     SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "vehicle.h"
0008 #include "json_p.h"
0009 #include "datatypes_p.h"
0010 #include "mergeutil_p.h"
0011 
0012 #include <QDebug>
0013 #include <QMetaEnum>
0014 #include <QVariant>
0015 
0016 #include <limits>
0017 
0018 using namespace KPublicTransport;
0019 
0020 namespace KPublicTransport {
0021 
0022 class VehicleSectionPrivate : public QSharedData
0023 {
0024 public:
0025     QString name;
0026     float platformPositionBegin = -1.0;
0027     float platformPositionEnd = -1.0;
0028     VehicleSection::Type type = VehicleSection::UnknownType;
0029     VehicleSection::Classes classes = VehicleSection::UnknownClass;
0030     VehicleSection::Features features = VehicleSection::NoFeatures;
0031     int deckCount = 1;
0032     VehicleSection::Sides connectedSides = VehicleSection::Front | VehicleSection::Back;
0033     QString platformSectionName;
0034 };
0035 
0036 class VehiclePrivate : public QSharedData
0037 {
0038 public:
0039     QString name;
0040     std::vector<VehicleSection> sections;
0041     Vehicle::Direction direction = Vehicle::UnknownDirection;
0042 };
0043 
0044 }
0045 
0046 KPUBLICTRANSPORT_MAKE_GADGET(VehicleSection)
0047 KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, QString, name, setName)
0048 KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, float, platformPositionBegin, setPlatformPositionBegin)
0049 KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, float, platformPositionEnd, setPlatformPositionEnd)
0050 KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, VehicleSection::Type, type, setType)
0051 KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, VehicleSection::Classes, classes, setClasses)
0052 KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, VehicleSection::Features, features, setFeatures)
0053 KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, int, deckCount, setDeckCount)
0054 KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, VehicleSection::Sides, connectedSides, setConnectedSides)
0055 KPUBLICTRANSPORT_MAKE_PROPERTY(VehicleSection, QString, platformSectionName, setPlatformSectionName)
0056 
0057 VehicleSection VehicleSection::merge(const VehicleSection &lhs, const VehicleSection &rhs)
0058 {
0059     if (lhs.name() != rhs.name()) { // safety check, as we don't properly check for equalness before merging yet
0060         return lhs;
0061     }
0062 
0063     auto res = lhs;
0064     res.setPlatformPositionBegin(lhs.platformPositionBegin() < 0.0 ? rhs.platformPositionBegin() : lhs.platformPositionBegin());
0065     res.setPlatformPositionEnd(lhs.platformPositionEnd() < 0.0 ? rhs.platformPositionEnd() : lhs.platformPositionEnd());
0066     res.setType(std::max(lhs.type(), rhs.type()));
0067     if (res.type() == VehicleSection::PassengerCar && lhs.type() != VehicleSection::UnknownType && rhs.type() != VehicleSection::UnknownType) {
0068         res.setType(std::min(lhs.type(), rhs.type()));
0069     }
0070     res.setClasses(lhs.classes() | rhs.classes());
0071     res.setFeatures(lhs.features() | rhs.features());
0072     res.setDeckCount(std::max(lhs.deckCount(), rhs.deckCount()));
0073     res.setConnectedSides(lhs.connectedSides() & rhs.connectedSides());
0074     res.setPlatformSectionName(MergeUtil::mergeString(lhs.platformSectionName(), rhs.platformSectionName()));
0075     return res;
0076 }
0077 
0078 QJsonObject VehicleSection::toJson(const VehicleSection &section)
0079 {
0080     return Json::toJson(section);
0081 }
0082 
0083 QJsonArray VehicleSection::toJson(const std::vector<VehicleSection> &sections)
0084 {
0085     return Json::toJson(sections);
0086 }
0087 
0088 VehicleSection VehicleSection::fromJson(const QJsonObject &obj)
0089 {
0090     return Json::fromJson<VehicleSection>(obj);
0091 }
0092 
0093 std::vector<VehicleSection> VehicleSection::fromJson(const QJsonArray &array)
0094 {
0095     return Json::fromJson<VehicleSection>(array);
0096 }
0097 
0098 QVariantList VehicleSection::featureList() const
0099 {
0100     QVariantList l;
0101     const auto me = QMetaEnum::fromType<VehicleSection::Features>();
0102     for (int i = 0; i < me.keyCount(); ++i) {
0103         if (features() & static_cast<VehicleSection::Feature>(1 << i))
0104             l.push_back(static_cast<VehicleSection::Feature>(1 << i));
0105     }
0106     return l;
0107 }
0108 
0109 bool VehicleSection::hasPlatformPosition() const
0110 {
0111     return d->platformPositionBegin >= 0.0 && d->platformPositionEnd >= 0.0;
0112 }
0113 
0114 KPUBLICTRANSPORT_MAKE_GADGET(Vehicle)
0115 KPUBLICTRANSPORT_MAKE_PROPERTY(Vehicle, QString, name, setName)
0116 KPUBLICTRANSPORT_MAKE_PROPERTY(Vehicle, Vehicle::Direction, direction, setDirection)
0117 
0118 bool Vehicle::isEmpty() const
0119 {
0120     return d->name.isEmpty() && d->sections.empty() && d->direction == Vehicle::UnknownDirection;
0121 }
0122 
0123 const std::vector<VehicleSection>& Vehicle::sections() const
0124 {
0125     return d->sections;
0126 }
0127 
0128 std::vector<VehicleSection>&& Vehicle::takeSections()
0129 {
0130     d.detach();
0131     return std::move(d->sections);
0132 }
0133 
0134 void Vehicle::setSections(std::vector<VehicleSection> &&sections)
0135 {
0136     d.detach();
0137     d->sections = std::move(sections);
0138 }
0139 
0140 void Vehicle::setSections(const std::vector<VehicleSection> &sections)
0141 {
0142     d.detach();
0143     d->sections = sections;
0144 }
0145 
0146 QVariantList Vehicle::sectionsVariant() const
0147 {
0148     QVariantList l;
0149     l.reserve(d->sections.size());
0150     std::transform(d->sections.begin(), d->sections.end(), std::back_inserter(l), [](const auto &sec) { return QVariant::fromValue(sec); });
0151     return l;
0152 }
0153 
0154 float Vehicle::platformPositionBegin() const
0155 {
0156     float p = std::numeric_limits<float>::max();
0157     for (const auto &section : sections()) {
0158         p = std::min(p, section.platformPositionBegin());
0159     }
0160     return p;
0161 }
0162 
0163 float Vehicle::platformPositionEnd() const
0164 {
0165     float p = -1.0f;
0166     for (const auto &section : sections()) {
0167         p = std::max(p, section.platformPositionEnd());
0168     }
0169     return p;
0170 }
0171 
0172 float Vehicle::platformPositionForSection(const QString &sectionName) const
0173 {
0174     for (const auto &section : sections()) {
0175         if (section.name() == sectionName) {
0176             return (section.platformPositionBegin() + section.platformPositionEnd()) / 2.0f;
0177         }
0178     }
0179     return -1.0f;
0180 }
0181 
0182 Vehicle Vehicle::merge(const Vehicle &lhs, const Vehicle &rhs)
0183 {
0184     Vehicle res;
0185     res.setDirection(lhs.direction() == Vehicle::UnknownDirection ? rhs.direction() : lhs.direction());
0186     res.setName(MergeUtil::mergeString(lhs.name(), rhs.name()));
0187 
0188     if (lhs.sections().size() == rhs.sections().size()) {
0189         std::vector<VehicleSection> secs;
0190         secs.reserve(lhs.sections().size());
0191         for (std::size_t i = 0; i < lhs.sections().size(); ++i) {
0192             const auto &lhsSec = lhs.sections()[i];
0193             const auto &rhsSec = rhs.sections()[i];
0194             secs.push_back(VehicleSection::merge(lhsSec, rhsSec));
0195         }
0196         res.setSections(std::move(secs));
0197     } else {
0198         res.setSections(lhs.sections().size() < rhs.sections().size() ? rhs.sections() : lhs.sections());
0199     }
0200 
0201     return res;
0202 }
0203 
0204 QJsonObject Vehicle::toJson(const Vehicle &vehicle)
0205 {
0206     auto obj = Json::toJson(vehicle);
0207     if (!vehicle.sections().empty()) {
0208         obj.insert(QLatin1String("sections"), VehicleSection::toJson(vehicle.sections()));
0209     }
0210     return obj;
0211 }
0212 
0213 QJsonArray Vehicle::toJson(const std::vector<Vehicle> &vehicles)
0214 {
0215     return Json::toJson(vehicles);
0216 }
0217 
0218 Vehicle Vehicle::fromJson(const QJsonObject &obj)
0219 {
0220     auto v = Json::fromJson<Vehicle>(obj);
0221     v.setSections(VehicleSection::fromJson(obj.value(QLatin1String("sections")).toArray()));
0222     return v;
0223 }
0224 
0225 std::vector<Vehicle> Vehicle::fromJson(const QJsonArray &array)
0226 {
0227     return Json::fromJson<Vehicle>(array);
0228 }
0229 
0230 bool Vehicle::hasPlatformPositions() const
0231 {
0232     return std::all_of(d->sections.begin(), d->sections.end(), [](const auto &p) { return p.hasPlatformPosition(); });
0233 }
0234 
0235 bool Vehicle::hasPlatformSectionNames() const
0236 {
0237     return std::none_of(d->sections.begin(), d->sections.end(), [](const auto &p) { return p.platformSectionName().isEmpty(); });
0238 }
0239 
0240 #include "moc_vehicle.cpp"