File indexing completed on 2024-07-14 14:25:21

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2011 Dennis Nienhüser <nienhueser@kde.org>
0004 //
0005 
0006 #ifndef MARBLE_OSMPARSER_H
0007 #define MARBLE_OSMPARSER_H
0008 
0009 #include "Writer.h"
0010 #include "OsmRegion.h"
0011 #include "OsmPlacemark.h"
0012 #include "OsmRegionTree.h"
0013 
0014 #include <QObject>
0015 #include <QFileInfo>
0016 #include <QHash>
0017 #include <QList>
0018 #include <QPair>
0019 
0020 namespace Marble
0021 {
0022 
0023 class GeoDataLineString;
0024 
0025 enum ElementType {
0026     NoType,
0027     NodeType,
0028     WayType,
0029     RelationType
0030 };
0031 
0032 enum RelationRole {
0033     None,
0034     Outer,
0035     Inner
0036 };
0037 
0038 struct OsmOsmRegion {
0039     OsmOsmRegion* parent;
0040     OsmRegion region;
0041 
0042     OsmOsmRegion() : parent( nullptr ) {}
0043 };
0044 
0045 struct Element {
0046     bool save;
0047     QString name;
0048     QString street;
0049     QString houseNumber;
0050     QString city;
0051     OsmPlacemark::OsmCategory category;
0052 
0053     Element() : save( false ),
0054         category( OsmPlacemark::UnknownCategory ) {}
0055 };
0056 
0057 struct Coordinate {
0058     float lon;
0059     float lat;
0060 
0061     Coordinate(float lon=0.0, float lat=0.0);
0062 };
0063 
0064 struct Node : public Element {
0065     float lon;
0066     float lat;
0067 
0068     operator OsmPlacemark() const;
0069     operator Coordinate() const;
0070 };
0071 
0072 struct Way : public Element {
0073     QList<int> nodes;
0074     bool isBuilding;
0075 
0076     operator OsmPlacemark() const;
0077     void setPosition( const QHash<int, Coordinate> &database, OsmPlacemark &placemark ) const;
0078     void setRegion( const QHash<int, Node> &database, const OsmRegionTree & tree, QList<OsmOsmRegion> & osmOsmRegions, OsmPlacemark &placemark ) const;
0079 };
0080 
0081 struct WayMerger {
0082 public:
0083     QList<Way> ways;
0084 
0085     WayMerger( const Way &way ) {
0086         ways << way;
0087     }
0088 
0089     bool compatible( const Way &aWay ) const {
0090         for( const Way & way: ways ) {
0091             if ( way.nodes.first() == aWay.nodes.first() ) return true;
0092             if ( way.nodes.last()  == aWay.nodes.first() ) return true;
0093             if ( way.nodes.first() == aWay.nodes.last() ) return true;
0094             if ( way.nodes.last()  == aWay.nodes.last() ) return true;
0095         }
0096 
0097         return false;
0098     }
0099 
0100     bool compatible( const WayMerger &other ) const {
0101         for( const Way & way: ways ) {
0102             if ( other.compatible( way ) ) {
0103                 return true;
0104             }
0105         }
0106 
0107         return false;
0108     }
0109 
0110     void merge( const WayMerger &other ) {
0111         ways << other.ways;
0112     }
0113 };
0114 
0115 struct Relation : public Element {
0116     QList<int> nodes;
0117     QList< QPair<int, RelationRole> > ways;
0118     QList<int> relations;
0119     QString name;
0120     bool isMultipolygon;
0121     bool isAdministrativeBoundary;
0122     int adminLevel;
0123 
0124     Relation() : isMultipolygon( false ),
0125         isAdministrativeBoundary( false ),
0126         adminLevel( 0 )
0127     {
0128         // nothing to do
0129     }
0130 };
0131 
0132 struct Statistic {
0133     unsigned int mergedWays;
0134     unsigned int uselessWays;
0135 
0136     Statistic() : mergedWays( 0 ),
0137         uselessWays( 0 )
0138     {}
0139 };
0140 
0141 class OsmParser : public QObject
0142 {
0143     Q_OBJECT
0144 public:
0145     explicit OsmParser( QObject *parent = nullptr );
0146 
0147     void addWriter( Writer* writer );
0148 
0149     void read( const QFileInfo &file, const QString &areaName );
0150 
0151     void writeKml( const QString &area, const QString &version, const QString &date, const QString &transport, const QString &payload, const QString &outputKml ) const;
0152 
0153 protected:
0154     virtual bool parse( const QFileInfo &file, int pass, bool &needAnotherPass ) = 0;
0155 
0156     bool shouldSave( ElementType type, const QString &key, const QString &value );
0157 
0158     void setCategory( Element &element, const QString &key, const QString &value );
0159 
0160     QHash<int, Coordinate> m_coordinates;
0161 
0162     QHash<int, Node> m_nodes;
0163 
0164     QHash<int, Way> m_ways;
0165 
0166     QHash<int, Relation> m_relations;
0167 
0168 private:
0169     GeoDataLinearRing *convexHull() const;
0170 
0171     void importMultipolygon( const Relation &relation );
0172 
0173     void importWay( QVector<Marble::GeoDataLineString> &ways, int id );
0174 
0175     QList< QList<Way> > merge( const QList<Way> &ways ) const;
0176 
0177     template<class T, class S>
0178     bool contains( const T &outer, const S &inner ) const {
0179         for ( int i = 0; i < inner.size(); ++i ) {
0180             if ( !outer.contains( inner[i] ) ) {
0181                 bool onBorder = false;
0182                 for ( int k=0; k<outer.size(); ++k ) {
0183                     if ( inner[i] == outer[k] ) {
0184                         onBorder = true;
0185                         break;
0186                     }
0187                 }
0188                 if ( !onBorder ) {
0189                     return false;
0190                 }
0191             }
0192         }
0193 
0194         return true;
0195     }
0196 
0197     QColor randomColor() const;
0198 
0199     Marble::GeoDataLineString reverse( const Marble::GeoDataLineString & string );
0200 
0201     QList<Writer*> m_writers;
0202 
0203     QList<OsmOsmRegion> m_osmOsmRegions;
0204 
0205     QList<OsmPlacemark> m_placemarks;
0206 
0207     QHash<QString, OsmPlacemark::OsmCategory> m_categoryMap;
0208 
0209     mutable Statistic m_statistic;
0210 
0211     GeoDataLinearRing* m_convexHull;
0212 };
0213 
0214 }
0215 
0216 #endif // MARBLE_OSMPARSER_H