File indexing completed on 2024-05-05 03:49:50

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2015 Marius-Valeriu Stanciu <stanciumarius94@gmail.com>
0004 //
0005 
0006 #ifndef MARBLE_OSMPLACEMARKDATA_H
0007 #define MARBLE_OSMPLACEMARKDATA_H
0008 
0009 // Qt
0010 #include <QHash>
0011 #include <QMetaType>
0012 #include <QString>
0013 
0014 // Marble
0015 #include "GeoDataCoordinates.h"
0016 #include <marble_export.h>
0017 #include "GeoDocument.h"
0018 
0019 class QXmlStreamAttributes;
0020 
0021 namespace Marble
0022 {
0023 
0024 /** Type of OSM element. */
0025 enum class OsmType {
0026     Node,
0027     Way,
0028     Relation
0029 };
0030 
0031 /** Identifier for an OSM element.
0032  *  @note OSM uses distinct id spaces for all its three basic element types, so just the numeric id
0033  *  on its own doesn't identify an element without knowing its type.
0034  */
0035 struct OsmIdentifier {
0036     inline OsmIdentifier() = default;
0037     inline OsmIdentifier(qint64 _id, OsmType _type) : id(_id), type(_type) {}
0038 
0039     qint64 id = 0;
0040     OsmType type = OsmType::Way;
0041 
0042     inline bool operator==(OsmIdentifier other) const { return id == other.id && type == other.type; }
0043 };
0044 
0045 /**
0046  * This class is used to encapsulate the osm data fields kept within a placemark's extendedData.
0047  * It stores OSM server generated data: id, version, changeset, uid, visible, user, timestamp;
0048  * It also stores a hash map of \<tags\> ( key-value mappings ) and a hash map of component osm
0049  * placemarks @see m_nodeReferences @see m_memberReferences
0050  *
0051  * The usual workflow with osmData goes as follows:
0052  *
0053  * Parsing stage:
0054  * The OsmParser parses tags (they have server-generated attributes), creates new placemarks and
0055  * assigns them new OsmPlacemarkData objects with all the needed information.
0056  *
0057  * Editing stage:
0058  * While editing placemarks that have OsmPlacemarkData, all relevant changes reflect on the
0059  * OsmPlacemarkData object as well, so as not to uncorrelate data from the actual placemarks.
0060  *
0061  * Writing stage:
0062  * The OsmObjectManager assigns OsmPlacemarkData objects to placemarks that do not have it
0063  * ( these are usually newly created placemarks within the editor, or placemarks loaded from
0064  * ".kml" files ). Placemarks that already have it, are simply written as-is.
0065  */
0066 class MARBLE_EXPORT OsmPlacemarkData: public GeoNode
0067 {
0068 
0069 public:
0070     OsmPlacemarkData();
0071 
0072     qint64 id() const;
0073     qint64 oid() const;
0074     QString version() const;
0075     QString changeset() const;
0076     QString uid() const;
0077     QString isVisible() const;
0078     QString user() const;
0079     QString timestamp() const;
0080     QString action() const;
0081     const char* nodeType() const override;
0082 
0083     void setId( qint64 id );
0084     void setVersion( const QString& version );
0085     void setChangeset( const QString& changeset );
0086     void setUid( const QString& uid );
0087     void setVisible( const QString& visible );
0088     void setUser( const QString& user );
0089     void setTimestamp( const QString& timestamp );
0090     void setAction( const QString& action );
0091 
0092 
0093     /**
0094      * @brief tagValue returns the value of the tag that has @p key as key
0095      * or an empty qstring if there is no such tag
0096      */
0097     QString tagValue( const QString &key ) const;
0098 
0099     /**
0100      * @brief addTag this function inserts a string key=value mapping,
0101      * equivalent to the \<tag k="@p key" v="@p value"\> osm core data
0102      * element
0103      */
0104     void addTag( const QString& key, const QString& value );
0105 
0106     /**
0107      * @brief removeTag removes the tag from the tag hash
0108      */
0109     void removeTag( const QString& key );
0110 
0111     /**
0112      * @brief containsTag returns true if the tag hash contains an entry with
0113      * the @p key as key and @p value as value
0114      */
0115     bool containsTag( const QString& key, const QString& value ) const;
0116 
0117     /**
0118      * @brief containsTagKey returns true if the tag hash contains an entry with
0119      * the @p key as key
0120      */
0121     bool containsTagKey( const QString& key ) const;
0122 
0123     /**
0124      * @brief tagValue returns a pointer to the tag that has @p key as key
0125      * or the end iterator if there is no such tag
0126      */
0127     QHash<QString, QString>::const_iterator findTag(const QString &key) const;
0128 
0129     /**
0130      * @brief iterators for the tags hash.
0131      */
0132     QHash< QString, QString >::const_iterator tagsBegin() const;
0133     QHash< QString, QString >::const_iterator tagsEnd() const;
0134 
0135 
0136     /**
0137      * @brief this function returns the osmData associated with a nd
0138      */
0139     OsmPlacemarkData &nodeReference( const GeoDataCoordinates& coordinates );
0140     OsmPlacemarkData nodeReference( const GeoDataCoordinates& coordinates ) const;
0141 
0142     /**
0143      * @brief addRef this function inserts a GeoDataCoordinates = OsmPlacemarkData
0144      * mapping into the reference hash, equivalent to the \<member ref="@p key" \>
0145      * osm core data element
0146      */
0147     void addNodeReference( const GeoDataCoordinates& key, const OsmPlacemarkData &value );
0148     void removeNodeReference( const GeoDataCoordinates& key );
0149     bool containsNodeReference( const GeoDataCoordinates& key ) const;
0150 
0151     /**
0152      * @brief changeNodeReference is a convenience function that allows the quick change of
0153      * a node hash entry. This is generally used to update the osm data in case
0154      * nodes are being moved in the editor.
0155      */
0156     void changeNodeReference( const GeoDataCoordinates& oldKey, const GeoDataCoordinates &newKey );
0157 
0158     /**
0159      * @brief iterators for the reference hashes.
0160      */
0161     QHash< GeoDataCoordinates, OsmPlacemarkData > & nodeReferences();
0162     QHash< GeoDataCoordinates, OsmPlacemarkData >::const_iterator nodeReferencesBegin() const;
0163     QHash< GeoDataCoordinates, OsmPlacemarkData >::const_iterator nodeReferencesEnd() const;
0164 
0165 
0166 
0167     /**
0168      * @brief this function returns the osmData associated with a member boundary's index
0169      * -1 represents the outer boundary of a polygon, and 0,1,2... the inner boundaries,
0170      * in the order provided by polygon->innerBoundaries();
0171      */
0172     OsmPlacemarkData &memberReference( int key );
0173     OsmPlacemarkData memberReference( int key ) const;
0174 
0175     /**
0176      * @brief addRef this function inserts a int = OsmplacemarkData
0177      * mapping into the reference hash, equivalent to the osm \<nd ref="@p boundary of index @key" \>
0178      * core data element
0179      * @see m_memberReferences
0180      */
0181     void addMemberReference( int key, const OsmPlacemarkData &value );
0182     void removeMemberReference( int key );
0183     bool containsMemberReference( int key ) const;
0184 
0185     QHash< int, OsmPlacemarkData > & memberReferences();
0186     QHash< int, OsmPlacemarkData >::const_iterator memberReferencesBegin() const;
0187     QHash< int, OsmPlacemarkData >::const_iterator memberReferencesEnd() const;
0188 
0189     /**
0190      * @brief addRelation calling this makes the osm placemark a member of the relation
0191      * with @p id as id, while having the role @p role
0192      */
0193     void addRelation( qint64 id, OsmType type, const QString &role );
0194     void removeRelation( qint64 id );
0195     bool containsRelation( qint64 id ) const;
0196 
0197     QHash< OsmIdentifier, QString >::const_iterator relationReferencesBegin() const;
0198     QHash< OsmIdentifier, QString >::const_iterator relationReferencesEnd() const;
0199 
0200     /**
0201      * @brief isNull returns false if the osmData is loaded from a source
0202      * or true if its just default constructed
0203      */
0204     bool isNull() const;
0205 
0206     /**
0207      * @brief isEmpty returns true if no attribute other than the id has been set
0208      */
0209     bool isEmpty() const;
0210 
0211     /**
0212      * @brief fromParserAttributes is a convenience function that parses all osm-related
0213      * arguments of a tag
0214      * @return an OsmPlacemarkData object containing all the necessary data
0215      */
0216     static OsmPlacemarkData fromParserAttributes( const QXmlStreamAttributes &attributes );
0217 
0218 private:
0219     qint64 m_id;
0220     QHash<QString, QString> m_tags;
0221 
0222     /**
0223      * @brief m_ndRefs is used to store a way's component nodes
0224      * ( It is empty for other placemark types )
0225      */
0226     QHash< GeoDataCoordinates, OsmPlacemarkData > m_nodeReferences;
0227 
0228     /**
0229      * @brief m_memberRefs is used to store a polygon's member boundaries
0230      *  the key represents the index of the boundary within the polygon geometry:
0231      *  -1 represents the outerBoundary, and 0,1,2... its innerBoundaries, in the
0232      *  order provided by polygon->innerBoundaries()
0233      */
0234     QHash<int, OsmPlacemarkData> m_memberReferences;
0235 
0236     /**
0237      * @brief m_relationReferences is used to store the relations the placemark is part of
0238      * and the role it has within them.
0239      * Eg. an entry ( "123", "stop" ) means that the parent placemark is a member of
0240      * the relation with id "123", while having the "stop" role
0241      */
0242     QHash<OsmIdentifier, QString> m_relationReferences;
0243 
0244 };
0245 
0246 }
0247 
0248 // Makes qvariant_cast possible for OsmPlacemarkData objects
0249 Q_DECLARE_METATYPE( Marble::OsmPlacemarkData )
0250 
0251 #endif