File indexing completed on 2024-12-08 10:15:42

0001 /*
0002     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "lineinfo.h"
0008 #include "../lib/datatypes/linecompare_p.h"
0009 
0010 #include <QDebug>
0011 
0012 enum {
0013     BoundingBoxSizeWarning = 12'000'000, // warning threshold for bbox sizes, in 1/1e7-th degree
0014 };
0015 
0016 LineInfo::LineInfo() = default;
0017 LineInfo::~LineInfo() = default;
0018 
0019 bool LineInfo::isUseful(const LineInfo& info)
0020 {
0021     if (info.name.isEmpty())
0022         return false;
0023 
0024     switch (info.mode) {
0025         case Unknown:
0026             return false;
0027         case Train:
0028         case LongDistance:
0029         case LocalTrain:
0030             return !info.lineLogos.empty();
0031         case RapidTransit:
0032         case Tram:
0033         case Subway:
0034             return info.color.isValid() || !info.lineLogos.isEmpty() || !info.productLogos.isEmpty();
0035     }
0036     return false;
0037 }
0038 
0039 static LineInfo::Mode lineModeStringToMode(const QByteArray &s)
0040 {
0041    if (s == "subway") {
0042         return LineInfo::Subway;
0043     }
0044     if (s == "tram") {
0045         return LineInfo::Tram;
0046     }
0047     if (s == "light_rail" || s == "commuter" || s == "suburban") {
0048         return LineInfo::RapidTransit;
0049     }
0050     if (s == "national" || s == "long_distance" || s == "international" || s == "high_speed") {
0051         return LineInfo::LongDistance;
0052     }
0053     if (s == "regional") {
0054         return LineInfo::LocalTrain;
0055     }
0056     return LineInfo::Unknown;
0057 }
0058 
0059 LineInfo::Mode LineInfo::determineMode(const OSM::Relation &rel)
0060 {
0061     auto m = lineModeStringToMode(OSM::tagValue(rel, "route_master"));
0062     if (m != Unknown) return m;
0063 
0064     m = lineModeStringToMode(OSM::tagValue(rel, "route"));
0065     if (m != Unknown) return m;
0066 
0067     return std::max(lineModeStringToMode(OSM::tagValue(rel, "line")),
0068            std::max(lineModeStringToMode(OSM::tagValue(rel, "service")),
0069                     lineModeStringToMode(OSM::tagValue(rel, "passenger"))));
0070 }
0071 
0072 LineInfo LineInfo::fromRelation(const OSM::Relation &rel)
0073 {
0074     LineInfo info;
0075     info.relId = rel.id;
0076 
0077     // check for under constructions or out-of-service tags
0078     const auto underConstruction = OSM::tagValue(rel, "construction");
0079     if (underConstruction == "yes") {
0080         return info;
0081     }
0082 
0083     info.name = QString::fromUtf8(OSM::tagValue(rel, "ref")).trimmed();
0084     const auto colStr = OSM::tagValue(rel, "colour");
0085     if (!colStr.isEmpty()) {
0086         info.color = QColor(QString::fromUtf8(colStr));
0087     }
0088     info.wdId = Wikidata::Q(OSM::tagValue(rel, "wikidata"));
0089     info.mode = determineMode(rel);
0090 
0091     info.bbox = rel.bbox;
0092     if (isUseful(info) && (info.bbox.width() > BoundingBoxSizeWarning || info.bbox.height() > BoundingBoxSizeWarning)) {
0093         qWarning() << "Suspicious bbox size:" << info.relId << info.name << info.bbox;
0094     }
0095 
0096     return info;
0097 }
0098 
0099 void LineInfo::merge(LineInfo &lhs, const LineInfo &rhs)
0100 {
0101     Q_ASSERT(!lhs.name.isEmpty());
0102     if (!rhs.name.isEmpty() && !KPublicTransport::Internal::isSameLineName(lhs.name, rhs.name, KPublicTransport::Internal::StrictCompare)) {
0103         qDebug() << "OSM name conflict:" << lhs << rhs;
0104     }
0105 
0106     if (lhs.color.isValid() && rhs.color.isValid() && lhs.color != rhs.color) {
0107         qWarning() << "OSM color conflict:" << lhs << rhs;
0108     } else if (rhs.color.isValid()) {
0109         lhs.color = rhs.color;
0110     }
0111     if (lhs.wdId.isValid() && rhs.wdId.isValid() && lhs.wdId != rhs.wdId) {
0112         qWarning() << "wikidata id conflict:" << lhs << rhs;
0113     } else if (rhs.wdId.isValid()) {
0114         lhs.wdId = rhs.wdId;
0115     }
0116     if (lhs.mode != Unknown && rhs.mode != Unknown && lhs.mode != rhs.mode) {
0117         qWarning() << "OSM mode conflict:" << lhs << rhs;
0118     }
0119     lhs.mode = std::max(lhs.mode, rhs.mode);
0120     lhs.bbox = OSM::unite(lhs.bbox, rhs.bbox);
0121     if (LineInfo::isUseful(lhs) && (lhs.bbox.width() > BoundingBoxSizeWarning || lhs.bbox.height() > BoundingBoxSizeWarning)) {
0122         qWarning() << "Suspicious bbox size after merging:" << lhs << rhs;
0123     }
0124 }
0125 
0126 QDebug operator<<(QDebug debug, const LineInfo &info)
0127 {
0128     QDebugStateSaver saver(debug);
0129     debug.noquote().nospace()
0130         << info.name
0131         << " https://openstreetmap.org/relation/" << info.relId
0132         << " " << info.mode
0133         << (info.color.isValid() ? (QLatin1Char(' ') + info.color.name()) : QString())
0134         << (info.wdId.isValid() ? QString(QLatin1Char(' ')) : QString()) << info.wdId
0135         << " " << info.bbox;
0136     return debug;
0137 }