File indexing completed on 2025-01-05 03:59:00
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[QStringLiteral("road")] = RouteRoad; 0121 map[QStringLiteral("detour")] = RouteDetour; 0122 map[QStringLiteral("ferry")] = RouteFerry; 0123 map[QStringLiteral("train")] = RouteTrain; 0124 map[QStringLiteral("subway")] = RouteSubway; 0125 map[QStringLiteral("tram")] = RouteTram; 0126 map[QStringLiteral("bus")] = RouteBus; 0127 map[QStringLiteral("trolleybus")] = RouteTrolleyBus; 0128 map[QStringLiteral("bicycle")] = RouteBicycle; 0129 map[QStringLiteral("mtb")] = RouteMountainbike; 0130 map[QStringLiteral("foot")] = RouteFoot; 0131 map[QStringLiteral("hiking")] = GeoDataRelation::RouteHiking; 0132 map[QStringLiteral("horse")] = RouteHorse; 0133 map[QStringLiteral("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 }