File indexing completed on 2024-05-12 03:50:17

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2017 Dennis Nienhüser <nienhueser@kde.org>
0004 
0005 #include "GeoDataRelation.h"
0006 
0007 #include "GeoDataTypes.h"
0008 #include "OsmPlacemarkData.h"
0009 
0010 #include <QSet>
0011 
0012 namespace Marble
0013 {
0014 
0015 class GeoDataRelationPrivate
0016 {
0017 public:
0018     QSet<const GeoDataFeature*> m_features;
0019     OsmPlacemarkData m_osmData;
0020     QSet<qint64> m_memberIds;
0021 
0022     mutable GeoDataRelation::RelationType m_relationType = GeoDataRelation::UnknownType;
0023     mutable bool m_relationTypeDirty = true;
0024     static QHash<QString, GeoDataRelation::RelationType> s_relationTypes;
0025 };
0026 
0027 QHash<QString, GeoDataRelation::RelationType> GeoDataRelationPrivate::s_relationTypes;
0028 
0029 GeoDataRelation::GeoDataRelation() :
0030     GeoDataFeature(),
0031     d_ptr(new GeoDataRelationPrivate)
0032 {
0033     // nothing to do
0034 }
0035 
0036 GeoDataRelation::~GeoDataRelation()
0037 {
0038     delete d_ptr;
0039 }
0040 
0041 GeoDataRelation::GeoDataRelation(const GeoDataRelation &other) :
0042     GeoDataFeature(other),
0043     d_ptr(new GeoDataRelationPrivate)
0044 {
0045     Q_D(GeoDataRelation);
0046     d->m_features = other.d_func()->m_features;
0047     d->m_osmData = other.d_func()->m_osmData;
0048     d->m_memberIds = other.d_func()->m_memberIds;
0049     d->m_relationType = other.d_func()->m_relationType;
0050     d->m_relationTypeDirty = other.d_func()->m_relationTypeDirty;
0051 }
0052 
0053 GeoDataRelation &GeoDataRelation::operator=(GeoDataRelation other) // passed by value
0054 {
0055     GeoDataFeature::operator=(other);
0056     std::swap(*this->d_ptr, *other.d_ptr);
0057     return *this;
0058 }
0059 
0060 bool GeoDataRelation::operator<(const GeoDataRelation &other) const
0061 {
0062     if (relationType() == other.relationType()) {
0063         Q_D(const GeoDataRelation);
0064         auto const refA = d->m_osmData.tagValue(QStringLiteral("ref"));
0065         auto const refB = other.osmData().tagValue(QStringLiteral("ref"));
0066         if (refA == refB) {
0067             return name() < other.name();
0068         }
0069         return refA < refB;
0070     }
0071     return relationType() < other.relationType();
0072 }
0073 
0074 const char *GeoDataRelation::nodeType() const
0075 {
0076     return GeoDataTypes::GeoDataRelationType;
0077 }
0078 
0079 GeoDataFeature *GeoDataRelation::clone() const
0080 {
0081     return new GeoDataRelation(*this);
0082 }
0083 
0084 void GeoDataRelation::addMember(const GeoDataFeature *feature, qint64 id, OsmType type, const QString &role)
0085 {
0086     Q_D(GeoDataRelation);
0087     d->m_features << feature;
0088     d->m_osmData.addRelation(id, type, role);
0089     d->m_memberIds << id;
0090 }
0091 
0092 QSet<const GeoDataFeature *> GeoDataRelation::members() const
0093 {
0094     Q_D(const GeoDataRelation);
0095     return d->m_features;
0096 }
0097 
0098 OsmPlacemarkData &GeoDataRelation::osmData()
0099 {
0100     Q_D(GeoDataRelation);
0101     d->m_relationTypeDirty = true;
0102     return d->m_osmData;
0103 }
0104 
0105 const OsmPlacemarkData &GeoDataRelation::osmData() const
0106 {
0107     Q_D(const GeoDataRelation);
0108     return d->m_osmData;
0109 }
0110 
0111 GeoDataRelation::RelationType GeoDataRelation::relationType() const
0112 {
0113     Q_D(const GeoDataRelation);
0114     if (!d->m_relationTypeDirty) {
0115         return d->m_relationType;
0116     }
0117 
0118     if (GeoDataRelationPrivate::s_relationTypes.isEmpty()) {
0119         auto &map = GeoDataRelationPrivate::s_relationTypes;
0120         map["road"] = RouteRoad;
0121         map["detour"] = RouteDetour;
0122         map["ferry"] = RouteFerry;
0123         map["train"] = RouteTrain;
0124         map["subway"] = RouteSubway;
0125         map["tram"] = RouteTram;
0126         map["bus"] = RouteBus;
0127         map["trolleybus"] = RouteTrolleyBus;
0128         map["bicycle"] = RouteBicycle;
0129         map["mtb"] = RouteMountainbike;
0130         map["foot"] = RouteFoot;
0131         map["hiking"] = GeoDataRelation::RouteHiking;
0132         map["horse"] = RouteHorse;
0133         map["inline_skates"] = RouteInlineSkates;
0134     }
0135 
0136     d->m_relationType = GeoDataRelation::UnknownType;
0137     d->m_relationTypeDirty = false;
0138     if (d->m_osmData.containsTag(QStringLiteral("type"), QStringLiteral("route"))) {
0139         auto const route = d->m_osmData.tagValue(QStringLiteral("route"));
0140         if (route == QStringLiteral("piste")) {
0141             auto const piste = d->m_osmData.tagValue(QStringLiteral("piste:type"));
0142             if (piste == QStringLiteral("downhill")) {
0143                 d->m_relationType = RouteSkiDownhill;
0144             } else if (piste == QStringLiteral("nordic")) {
0145                 d->m_relationType = RouteSkiNordic;
0146             } else if (piste == QStringLiteral("skitour")) {
0147                 d->m_relationType = RouteSkitour;
0148             } else if (piste == QStringLiteral("sled")) {
0149                 d->m_relationType = RouteSled;
0150             }
0151         } else {
0152             d->m_relationType = GeoDataRelationPrivate::s_relationTypes.value(route, UnknownType);
0153         }
0154     }
0155 
0156     return d->m_relationType;
0157 }
0158 
0159 QSet<qint64> GeoDataRelation::memberIds() const
0160 {
0161     Q_D(const GeoDataRelation);
0162     return d->m_memberIds;
0163 }
0164 
0165 bool GeoDataRelation::containsAnyOf(const QSet<qint64> &memberIds) const
0166 {
0167     Q_D(const GeoDataRelation);
0168     return d->m_memberIds.intersects(memberIds);
0169 }
0170 
0171 Q_DECLARE_OPERATORS_FOR_FLAGS(GeoDataRelation::RelationTypes)
0172 
0173 }