diff --git a/src/lib/marble/MarbleWidgetInputHandler.h b/src/lib/marble/MarbleWidgetInputHandler.h index d3b050bc2..a09372002 100644 --- a/src/lib/marble/MarbleWidgetInputHandler.h +++ b/src/lib/marble/MarbleWidgetInputHandler.h @@ -1,57 +1,57 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2005-2007 Torsten Rahn // Copyright 2007 Inge Wallin // Copyright 2014 Adam Dabrowski // #ifndef MARBLE_MARBLEWIDGETINPUTHANDLER_H #define MARBLE_MARBLEWIDGETINPUTHANDLER_H #include #include #include "MarbleInputHandler.h" namespace Marble { class MarbleWidget; class RenderPlugin; class MarbleWidgetInputHandlerPrivate; class MARBLE_EXPORT MarbleWidgetInputHandler : public MarbleDefaultInputHandler { Q_OBJECT public: MarbleWidgetInputHandler(MarbleAbstractPresenter *marblePresenter, MarbleWidget *marbleWidget); void setDebugModeEnabled(bool enabled); private Q_SLOTS: void installPluginEventFilter(RenderPlugin *renderPlugin) override; void showLmbMenu(int x, int y) override; void showRmbMenu(int x, int y) override; void openItemToolTip() override; void setCursor(const QCursor &cursor) override; private: bool handleKeyPress(QKeyEvent* event) override; AbstractSelectionRubber *selectionRubber() override; bool layersEventFilter(QObject *o, QEvent *e) override; - typedef QSharedPointer MarbleWidgetInputHandlerPrivatePtr; + using MarbleWidgetInputHandlerPrivatePtr = QSharedPointer; MarbleWidgetInputHandlerPrivatePtr d; friend class MarbleWidgetInputHandlerPrivate; Q_DISABLE_COPY(MarbleWidgetInputHandler) }; } #endif diff --git a/src/lib/marble/declarative/MarbleQuickItem.h b/src/lib/marble/declarative/MarbleQuickItem.h index 28be60d6c..e37a3752e 100644 --- a/src/lib/marble/declarative/MarbleQuickItem.h +++ b/src/lib/marble/declarative/MarbleQuickItem.h @@ -1,251 +1,251 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2014 Adam Dabrowski // #ifndef MARBLEQUICKITEM_H #define MARBLEQUICKITEM_H #include "marble_declarative_export.h" #include #include #include "GeoDataAccuracy.h" #include "MarbleGlobal.h" #include "PositionProviderPluginInterface.h" #include "MarbleMap.h" #include "Placemark.h" #include "Coordinate.h" namespace Marble { class GeoDataLatLonBox; class GeoDataPlacemark; class MarbleModel; class MarbleInputHandler; class MarbleQuickItemPrivate; //Class is still being developed class MARBLE_DECLARATIVE_EXPORT MarbleQuickItem : public QQuickPaintedItem { Q_OBJECT Q_ENUMS(Projection) Q_PROPERTY(int mapWidth READ mapWidth WRITE setMapWidth NOTIFY mapWidthChanged) Q_PROPERTY(int mapHeight READ mapHeight WRITE setMapHeight NOTIFY mapHeightChanged) Q_PROPERTY(int zoom READ zoom WRITE setZoom NOTIFY zoomChanged) Q_PROPERTY(int radius READ radius WRITE setRadius NOTIFY radiusChanged) Q_PROPERTY(bool showFrameRate READ showFrameRate WRITE setShowFrameRate NOTIFY showFrameRateChanged) Q_PROPERTY(Projection projection READ projection WRITE setProjection NOTIFY projectionChanged) Q_PROPERTY(QString mapThemeId READ mapThemeId WRITE setMapThemeId NOTIFY mapThemeIdChanged) Q_PROPERTY(bool showAtmosphere READ showAtmosphere WRITE setShowAtmosphere NOTIFY showAtmosphereChanged) Q_PROPERTY(bool showCompass READ showCompass WRITE setShowCompass NOTIFY showCompassChanged) Q_PROPERTY(bool showClouds READ showClouds WRITE setShowClouds NOTIFY showCloudsChanged) Q_PROPERTY(bool showCrosshairs READ showCrosshairs WRITE setShowCrosshairs NOTIFY showCrosshairsChanged) Q_PROPERTY(bool showGrid READ showGrid WRITE setShowGrid NOTIFY showGridChanged) Q_PROPERTY(bool showOverviewMap READ showOverviewMap WRITE setShowOverviewMap NOTIFY showOverviewMapChanged) Q_PROPERTY(bool showOtherPlaces READ showOtherPlaces WRITE setShowOtherPlaces NOTIFY showOtherPlacesChanged) Q_PROPERTY(bool showScaleBar READ showScaleBar WRITE setShowScaleBar NOTIFY showScaleBarChanged) Q_PROPERTY(bool showBackground READ showBackground WRITE setShowBackground NOTIFY showBackgroundChanged) Q_PROPERTY(bool showPositionMarker READ showPositionMarker WRITE setShowPositionMarker NOTIFY showPositionMarkerChanged) Q_PROPERTY(bool showPublicTransport READ showPublicTransport WRITE setShowPublicTransport NOTIFY showPublicTransportChanged) Q_PROPERTY(bool showOutdoorActivities READ showOutdoorActivities WRITE setShowOutdoorActivities NOTIFY showOutdoorActivitiesChanged) Q_PROPERTY(QString positionProvider READ positionProvider WRITE setPositionProvider NOTIFY positionProviderChanged) Q_PROPERTY(bool positionAvailable READ positionAvailable NOTIFY positionAvailableChanged) Q_PROPERTY(bool positionVisible READ positionVisible NOTIFY positionVisibleChanged) Q_PROPERTY(MarbleMap* marbleMap READ map NOTIFY marbleMapChanged) Q_PROPERTY(Placemark* currentPosition READ currentPosition NOTIFY currentPositionChanged) Q_PROPERTY(qreal speed READ speed NOTIFY speedChanged) Q_PROPERTY(qreal angle READ angle NOTIFY angleChanged) Q_PROPERTY(bool inertialGlobeRotation READ inertialGlobeRotation WRITE setInertialGlobeRotation NOTIFY inertialGlobeRotationChanged) Q_PROPERTY(bool animationViewContext READ animationViewContext WRITE setAnimationViewContext NOTIFY animationViewContextChanged) Q_PROPERTY(QQmlComponent* placemarkDelegate READ placemarkDelegate WRITE setPlacemarkDelegate NOTIFY placemarkDelegateChanged) public: explicit MarbleQuickItem(QQuickItem *parent = nullptr); enum Projection{ Spherical = Marble::Spherical, Equirectangular = Marble::Equirectangular, Mercator = Marble::Mercator, Gnomonic = Marble::Gnomonic, Stereographic = Marble::Stereographic, LambertAzimuthal = Marble::LambertAzimuthal, AzimuthalEquidistant = Marble::AzimuthalEquidistant, VerticalPerspective = Marble::VerticalPerspective }; MarbleInputHandler *inputHandler(); int zoom() const; int radius() const; public Q_SLOTS: void goHome(); void setZoom(int zoom, FlyToMode mode = Instant); Q_INVOKABLE void setZoomToMaximumLevel(); void setRadius(int radius); void centerOn(const GeoDataPlacemark& placemark, bool animated = false); void centerOn(const GeoDataLatLonBox& box, bool animated = false); void centerOn(const GeoDataCoordinates& coordinate); void centerOn(qreal longitude, qreal latitude); Q_INVOKABLE void centerOnCoordinates(qreal longitude, qreal latitude); Q_INVOKABLE void centerOnCurrentPosition(); Q_INVOKABLE void selectPlacemarkAt(int x, int y); void zoomIn(FlyToMode mode = Automatic); void zoomOut(FlyToMode mode = Automatic); Q_INVOKABLE void handlePinchStarted(const QPointF &point); Q_INVOKABLE void handlePinchFinished(const QPointF &point); Q_INVOKABLE void handlePinchUpdated(const QPointF &point, qreal scale); void setMapWidth(int mapWidth); void setMapHeight(int mapHeight); void setShowFrameRate(bool showFrameRate); void setProjection(Projection projection); void setMapThemeId(const QString& mapThemeId); void setShowAtmosphere(bool showAtmosphere); void setShowCompass(bool showCompass); void setShowClouds(bool showClouds); void setShowCrosshairs(bool showCrosshairs); void setShowGrid(bool showGrid); void setShowOverviewMap(bool showOverviewMap); void setShowOtherPlaces(bool showOtherPlaces); void setShowScaleBar(bool showScaleBar); void setShowBackground(bool showBackground); void setShowPositionMarker(bool showPositionMarker); void setShowPublicTransport(bool showPublicTransport); void setShowOutdoorActivities(bool showOutdoorActivities); void setPositionProvider(const QString & positionProvider); void setInertialGlobeRotation(bool inertialGlobeRotation); void setAnimationViewContext(bool animationViewContext); void setPluginSetting(const QString &plugin, const QString &key, const QString &value); void setPropertyEnabled(const QString &property, bool enabled); bool isPropertyEnabled(const QString &property) const; Q_INVOKABLE void setShowRuntimeTrace(bool showRuntimeTrace); Q_INVOKABLE void setShowDebugPolygons(bool showDebugPolygons); Q_INVOKABLE void setShowDebugPlacemarks(bool showDebugPlacemarks); Q_INVOKABLE void setShowDebugBatches(bool showDebugBatches); void setPlacemarkDelegate(QQmlComponent* placemarkDelegate); Q_INVOKABLE void loadSettings(); Q_INVOKABLE void writeSettings(); Q_INVOKABLE void reloadTiles(); Q_INVOKABLE void highlightRouteRelation(qint64 osmId, bool enabled); Q_INVOKABLE void setRelationTypeVisible(const QString &relationType, bool visible); Q_INVOKABLE bool isRelationTypeVisible(const QString &relationType) const; public: void paint(QPainter *painter) override; // QQmlParserStatus interface public: void classBegin() override; void componentComplete() override; public: virtual bool layersEventFilter(QObject *o, QEvent *e); int mapWidth() const; int mapHeight() const; bool showFrameRate() const; Projection projection() const; QString mapThemeId() const; bool showAtmosphere() const; bool showCompass() const; bool showClouds() const; bool showCrosshairs() const; bool showGrid() const; bool showOverviewMap() const; bool showOtherPlaces() const; bool showScaleBar() const; bool showBackground() const; bool showPositionMarker() const; bool showPublicTransport() const; bool showOutdoorActivities() const; QString positionProvider() const; bool positionAvailable() const; bool positionVisible() const; Q_INVOKABLE qreal distanceFromPointToCurrentLocation(const QPoint & position) const; Q_INVOKABLE qreal angleFromPointToCurrentLocation(const QPoint & position) const; Placemark* currentPosition() const; Q_INVOKABLE QPointF screenCoordinatesFromCoordinate(Coordinate * coordinate) const; qreal speed() const; qreal angle() const; MarbleModel* model(); const MarbleModel* model() const; MarbleMap* map(); const MarbleMap* map() const; bool inertialGlobeRotation() const; bool animationViewContext() const; QQmlComponent* placemarkDelegate() const; void reverseGeocoding(const QPoint &point); Q_SIGNALS: void mapWidthChanged(int mapWidth); void mapHeightChanged(int mapHeight); void showFrameRateChanged(bool showFrameRate); void projectionChanged(Projection projection); void mapThemeIdChanged(const QString& mapThemeId); void showAtmosphereChanged(bool showAtmosphere); void showCompassChanged(bool showCompass); void showCloudsChanged(bool showClouds); void showCrosshairsChanged(bool showCrosshairs); void showGridChanged(bool showGrid); void showOverviewMapChanged(bool showOverviewMap); void showOtherPlacesChanged(bool showOtherPlaces); void showScaleBarChanged(bool showScaleBar); void showBackgroundChanged(bool showBackground); void showPositionMarkerChanged(bool showPositionMarker); void showPublicTransportChanged(bool showPublicTransport); void showOutdoorActivitiesChanged(bool showOutdoorActivities); void positionProviderChanged(const QString & positionProvider); void positionAvailableChanged(bool positionAvailable); void positionVisibleChanged(bool positionVisible); void marbleMapChanged(); void visibleLatLonAltBoxChanged(); void currentPositionChanged(Placemark* currentPosition); void angleChanged(); void speedChanged(); void zoomChanged(); void radiusChanged(int radius); void inertialGlobeRotationChanged(bool inertialGlobeRotation); void animationViewContextChanged(bool animationViewContext); void placemarkDelegateChanged(QQmlComponent* placemarkDelegate); protected: QObject *getEventFilter() const; void pinch(const QPointF& center, qreal scale, Qt::GestureState state); private Q_SLOTS: void resizeMap(); void positionDataStatusChanged(PositionProviderStatus status); void positionChanged(const GeoDataCoordinates &, GeoDataAccuracy); void updatePositionVisibility(); void updateCurrentPosition(const GeoDataCoordinates & coordinates); void updatePlacemarks(); void handleReverseGeocoding(const GeoDataCoordinates &coordinates, const GeoDataPlacemark &placemark); private: - typedef QSharedPointer MarbleQuickItemPrivatePtr; + using MarbleQuickItemPrivatePtr = QSharedPointer; MarbleQuickItemPrivatePtr d; friend class MarbleQuickItemPrivate; }; } #endif // MARBLEQUICKITEM_H diff --git a/src/lib/marble/geodata/data/GeoDataCoordinates.h b/src/lib/marble/geodata/data/GeoDataCoordinates.h index cd6cd7b22..c59e9d78f 100644 --- a/src/lib/marble/geodata/data/GeoDataCoordinates.h +++ b/src/lib/marble/geodata/data/GeoDataCoordinates.h @@ -1,431 +1,431 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2006-2007 Torsten Rahn // Copyright 2007-2008 Inge Wallin // Copyright 2008 Patrick Spendrin // Copyright 2015 Alejandro Garcia Montoro // #ifndef MARBLE_GEODATACOORDINATES_H #define MARBLE_GEODATACOORDINATES_H #include #include #include #include "geodata_export.h" #include "MarbleGlobal.h" class QString; namespace Marble { class GeoDataCoordinatesPrivate; class Quaternion; /** * @short A 3d point representation * * GeoDataCoordinates is the simple representation of a single three * dimensional point. It can be used all through out marble as the data type * for three dimensional objects. it comprises of a Quaternion for speed issues. * This class was introduced to reflect the difference between a simple 3d point * and the GeoDataGeometry object containing such a point. The latter is a * GeoDataPoint and is simply derived from GeoDataCoordinates. * @see GeoDataPoint */ class GEODATA_EXPORT GeoDataCoordinates { Q_DECLARE_TR_FUNCTIONS(GeoDataCoordinates) public: /** * @brief enum used constructor to specify the units used * * Internally we always use radian for mathematical convenience. * However the Marble's interfaces to the outside should default * to degrees. */ enum Unit{ Radian, Degree }; /** * @brief enum used to specify the notation / numerical system * * For degrees there exist two notations: * "Decimal" (base-10) and the "Sexagesimal DMS" (base-60) which is * traditionally used in cartography. Decimal notation * uses floating point numbers to specify parts of a degree. The * Sexagesimal DMS notation uses integer based * Degrees-(Arc)Minutes-(Arc)Seconds to describe parts of a degree. */ enum Notation{ Decimal, ///< "Decimal" notation (base-10) DMS, ///< "Sexagesimal DMS" notation (base-60) DM, ///< "Sexagesimal DM" notation (base-60) UTM, Astro /// < "RA and DEC" notation (used for astronomical sky coordinates) }; /** * @brief The BearingType enum specifies where to measure the bearing * along great circle arcs * * When traveling along a great circle arc defined by the two points * A and B, the bearing varies along the arc. The "InitialBearing" bearing * corresponds to the bearing value at A, the "FinalBearing" bearing to that * at B. */ enum BearingType { InitialBearing, FinalBearing }; // Type definitions - typedef QVector Vector; - typedef QVector PtrVector; + using Vector = QVector; + using PtrVector = QVector; GeoDataCoordinates( const GeoDataCoordinates& other ); /** * @brief constructs an invalid instance * * Constructs an invalid instance such that calling isValid() * on it will return @code false @endcode. */ GeoDataCoordinates(); /** * @brief create a geocoordinate from longitude and latitude * @param _lon longitude * @param _lat latitude * @param alt altitude in meters (default: 0) * @param _unit units that lon and lat get measured in * (default for Radian: north pole at pi/2, southpole at -pi/2) * @param _detail detail (default: 0) */ GeoDataCoordinates( qreal lon, qreal lat, qreal alt = 0, GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian, int detail = 0 ); virtual ~GeoDataCoordinates(); /** * @brief Returns @code true @endcode if the coordinate is valid, @code false @endcode otherwise. * @return whether the coordinate is valid * * A coordinate is valid, if at least one component has been set and the last * assignment was not an invalid GeoDataCoordinates object. */ bool isValid() const; /** * @brief (re)set the coordinates in a GeoDataCoordinates object * @param _lon longitude * @param _lat latitude * @param alt altitude in meters (default: 0) * @param _unit units that lon and lat get measured in * (default for Radian: north pole at pi/2, southpole at -pi/2) */ void set( qreal lon, qreal lat, qreal alt = 0, GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian ); /** * @brief use this function to get the longitude and latitude with one * call - use the unit parameter to switch between Radian and DMS * @param lon longitude * @param lat latitude * @param unit units that lon and lat get measured in * (default for Radian: north pole at pi/2, southpole at -pi/2) */ void geoCoordinates(qreal& lon, qreal& lat, GeoDataCoordinates::Unit unit) const; void geoCoordinates(qreal& lon, qreal& lat) const; /** * @brief use this function to get the longitude, latitude and altitude * with one call - use the unit parameter to switch between Radian and DMS * @param lon longitude * @param lat latitude * @param alt altitude in meters * @param unit units that lon and lat get measured in * (default for Radian: north pole at pi/2, southpole at -pi/2) */ void geoCoordinates(qreal& lon, qreal& lat, qreal& alt, GeoDataCoordinates::Unit unit) const; void geoCoordinates(qreal& lon, qreal& lat, qreal& alt) const; /** * @brief set the longitude in a GeoDataCoordinates object * @param _lon longitude * @param _unit units that lon and lat get measured in * (default for Radian: north pole at pi/2, southpole at -pi/2) */ void setLongitude( qreal lon, GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian ); /** * @brief retrieves the longitude of the GeoDataCoordinates object * use the unit parameter to switch between Radian and DMS * @param unit units that lon and lat get measured in * (default for Radian: north pole at pi/2, southpole at -pi/2) * @return longitude */ qreal longitude(GeoDataCoordinates::Unit unit) const; qreal longitude() const; /** * @brief retrieves the latitude of the GeoDataCoordinates object * use the unit parameter to switch between Radian and DMS * @param unit units that lon and lat get measured in * (default for Radian: north pole at pi/2, southpole at -pi/2) * @return latitude */ qreal latitude( GeoDataCoordinates::Unit unit ) const; qreal latitude() const; /** * @brief set the longitude in a GeoDataCoordinates object * @param _lat longitude * @param _unit units that lon and lat get measured in * (default for Radian: north pole at pi/2, southpole at -pi/2) */ void setLatitude( qreal lat, GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian ); /** * @brief return the altitude of the Point in meters */ qreal altitude() const; /** * @brief set the altitude of the Point in meters * @param altitude altitude */ void setAltitude( const qreal altitude ); /** * @brief retrieves the UTM zone of the GeoDataCoordinates object. * If the point is located on one of the poles (latitude < 80S or * latitude > 84N) there is no UTM zone associated; in this case, * 0 is returned. * @return UTM zone. */ int utmZone() const; /** * @brief retrieves the UTM easting of the GeoDataCoordinates object, * in meters. * @return UTM easting */ qreal utmEasting() const; /** * @brief retrieves the UTM latitude band of the GeoDataCoordinates object * @return UTM latitude band */ QString utmLatitudeBand() const; /** * @brief retrieves the UTM northing of the GeoDataCoordinates object, * in meters * @return UTM northing */ qreal utmNorthing() const; /** * @brief return the detail flag * detail range: 0 for most important points, 5 for least important */ quint8 detail() const; /** * @brief set the detail flag * @param det detail */ void setDetail(quint8 detail); /** * @brief Rotates one coordinate around another. * @param axis The coordinate that serves as a rotation axis * @param angle Rotation angle * @param unit Unit of the result * @return The coordinate rotated in anticlockwise direction */ GeoDataCoordinates rotateAround( const GeoDataCoordinates &axis, qreal angle, Unit unit = Radian ) const; /** * @brief Returns the bearing (true bearing, the angle between the line defined * by this point and the other and the prime meridian) * @param other The second point that, together with this point, defines a line * @param unit Unit of the result * @return The true bearing in the requested unit, not range normalized, * in clockwise direction, with the value 0 corresponding to north */ qreal bearing( const GeoDataCoordinates &other, Unit unit = Radian, BearingType type = InitialBearing ) const; /** * @brief Returns the coordinates of the resulting point after moving this point * according to the distance and bearing parameters * @param bearing the same as above * @param distance the distance on a unit sphere */ GeoDataCoordinates moveByBearing( qreal bearing, qreal distance ) const; /** * @brief return a Quaternion with the used coordinates */ const Quaternion &quaternion() const; /** * @brief slerp (spherical linear) interpolation between this coordinate and the given target coordinate * @param target Destination coordinate * @param t Fraction 0..1 to weight between this and target * @return Interpolated coordinate between this (t<=0.0) and target (t>=1.0) */ GeoDataCoordinates interpolate( const GeoDataCoordinates &target, double t ) const; /** * @brief squad (spherical and quadrangle) interpolation between b and c * @param before First base point * @param target Third base point (second interpolation point) * @param after Fourth base point * @param t Offset between b (t<=0) and c (t>=1) */ GeoDataCoordinates interpolate( const GeoDataCoordinates &before, const GeoDataCoordinates &target, const GeoDataCoordinates &after, double t ) const; /** * @brief return whether our coordinates represent a pole * This method can be used to check whether the coordinate equals one of * the poles. */ bool isPole( Pole = AnyPole ) const; /** * @brief This method calculates the shortest distance between two points on a sphere. * @brief See: http://en.wikipedia.org/wiki/Great-circle_distance */ qreal sphericalDistanceTo(const GeoDataCoordinates &other) const; /** * @brief return Notation of string representation */ static GeoDataCoordinates::Notation defaultNotation(); /** * @brief set the Notation of the string representation * @param notation Notation */ static void setDefaultNotation( GeoDataCoordinates::Notation notation ); /** * @brief normalize the longitude to always be -M_PI <= lon <= +M_PI (Radian). * @param lon longitude */ static qreal normalizeLon( qreal lon, GeoDataCoordinates::Unit = GeoDataCoordinates::Radian ); /** * @brief normalize latitude to always be in -M_PI / 2. <= lat <= +M_PI / 2 (Radian). * @param lat latitude */ static qreal normalizeLat( qreal lat, GeoDataCoordinates::Unit = GeoDataCoordinates::Radian ); /** * @brief normalize both longitude and latitude at the same time * This method normalizes both latitude and longitude, so that the * latitude and the longitude stay within the "usual" range. * NOTE: If the latitude exceeds M_PI/2 (+90.0 deg) or -M_PI/2 (-90.0 deg) * then this will be interpreted as a pole traversion where the point will * end up on the opposite side of the globe. Therefore the longitude will * change by M_PI (180 deg). * If you don't want this behaviour use both normalizeLat() and * normalizeLon() instead. * @param lon the longitude value * @param lat the latitude value */ static void normalizeLonLat( qreal &lon, qreal &lat, GeoDataCoordinates::Unit = GeoDataCoordinates::Radian ); /** * @brief try to parse the string into a coordinate pair * @param successful becomes true if the conversion succeeds * @return the geodatacoordinates */ static GeoDataCoordinates fromString( const QString &string, bool& successful ); /** * @brief return a string representation of the coordinate * this is a convenience function which uses the default notation */ QString toString() const; /** * @brief return a string with the notation given by notation * * @param notation set a notation different from the default one * @param precision set the number of digits below degrees. * The precision depends on the current notation: * For Decimal representation the precision is the number of * digits after the decimal point. * In DMS a precision of 1 or 2 shows the arc minutes; a precision * of 3 or 4 will show arc seconds. A precision beyond that will * increase the number of digits after the arc second decimal point. */ QString toString( GeoDataCoordinates::Notation notation, int precision = -1 ) const; static QString lonToString( qreal lon, GeoDataCoordinates::Notation notation, GeoDataCoordinates::Unit unit = Radian, int precision = -1, char format = 'f' ); /** * @brief return a string representation of longitude of the coordinate * convenience function that uses the default notation */ QString lonToString() const; static QString latToString( qreal lat, GeoDataCoordinates::Notation notation, GeoDataCoordinates::Unit unit = Radian, int precision = -1, char format = 'f' ); /** * @brief return a string representation of latitude of the coordinate * convenience function that uses the default notation */ QString latToString() const; bool operator==(const GeoDataCoordinates &other) const; bool operator!=(const GeoDataCoordinates &other) const; GeoDataCoordinates& operator=( const GeoDataCoordinates &other ); /** Serialize the contents of the feature to @p stream. */ void pack(QDataStream &stream) const; /** Unserialize the contents of the feature from @p stream. */ void unpack(QDataStream &stream); private: void detach(); GeoDataCoordinatesPrivate *d; static GeoDataCoordinates::Notation s_notation; static const GeoDataCoordinates null; }; GEODATA_EXPORT uint qHash(const GeoDataCoordinates& coordinates ); } Q_DECLARE_METATYPE( Marble::GeoDataCoordinates ) #endif diff --git a/src/lib/marble/geodata/data/GeoDataLineString.h b/src/lib/marble/geodata/data/GeoDataLineString.h index e3a5bcb1c..2dd972dae 100644 --- a/src/lib/marble/geodata/data/GeoDataLineString.h +++ b/src/lib/marble/geodata/data/GeoDataLineString.h @@ -1,412 +1,412 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2008-2009 Torsten Rahn // Copyright 2009 Patrick Spendrin // #ifndef MARBLE_GEODATALINESTRING_H #define MARBLE_GEODATALINESTRING_H #include #include #include "MarbleGlobal.h" #include "geodata_export.h" #include "GeoDataGeometry.h" namespace Marble { class GeoDataCoordinates; class GeoDataLineStringPrivate; /*! \class GeoDataLineString \brief A LineString that allows to store a contiguous set of line segments. GeoDataLineString is a tool class that implements the LineString tag/class of the Open Geospatial Consortium standard KML 2.2. GeoDataLineString extends GeoDataGeometry to store and edit LineStrings. In the QPainter API "pure" LineStrings are also referred to as "polylines". As such they are similar to the outline of a non-closed QPolygon. Whenever a LineString is painted GeoDataLineStyle should be used to assign a color and line width. A GeoDataLineString consists of several (geodetic) nodes which are each connected through line segments. The nodes are stored as GeoDataCoordinates objects. The API which provides access to the nodes is similar to the API of QVector. GeoDataLineString allows LineStrings to be tessellated in order to make them follow the terrain and the curvature of the earth. The tessellation options allow for different ways of visualization: \li Not tessellated: A LineString that connects each two nodes directly and straight in screen coordinate space. \li A tessellated line: Each line segment is bent so that the LineString follows the curvature of the earth and its terrain. A tessellated line segment connects two nodes at the shortest possible distance ("along great circles"). \li A tessellated line that follows latitude circles whenever possible: In this case Latitude circles are followed as soon as two subsequent nodes have exactly the same amount of latitude. In all other places the line segments follow great circles. Some convenience methods have been added that allow to calculate the geodesic bounding box or the length of a LineString. */ class GEODATA_EXPORT GeoDataLineString : public GeoDataGeometry { public: - typedef QVector::Iterator Iterator; - typedef QVector::ConstIterator ConstIterator; - typedef QVector::const_iterator const_iterator; + using Iterator = QVector::Iterator; + using ConstIterator = QVector::ConstIterator; + using const_iterator = QVector::const_iterator; /*! \brief Creates a new LineString. */ explicit GeoDataLineString( TessellationFlags f = NoTessellation ); /*! \brief Creates a LineString from an existing geometry object. */ explicit GeoDataLineString( const GeoDataGeometry &other ); /*! \brief Destroys a LineString. */ ~GeoDataLineString() override; const char *nodeType() const override; EnumGeometryId geometryId() const override; GeoDataGeometry *copy() const override; /*! \brief Returns whether a LineString is a closed polygon. \return false if the LineString is not a LinearRing. */ virtual bool isClosed() const; /*! \brief Returns whether the LineString follows the earth's surface. \return true if the LineString's line segments follow the earth's surface and terrain along great circles. */ bool tessellate() const; /*! \brief Sets the tessellation property for the LineString. If \a tessellate is true then the LineString's line segments are bent and follow the earth's surface and terrain along great circles. If \a tessellate is false then the LineString's line segments are rendered as straight lines in screen coordinate space. */ void setTessellate( bool tessellate ); /*! \brief Returns the tessellation flags for a LineString. */ TessellationFlags tessellationFlags() const; /*! \brief Sets the given tessellation flags for a LineString. */ void setTessellationFlags( TessellationFlags f ); /*! \brief Reverses the LineString. @since 0.26.0 */ void reverse(); /*! \brief Returns the smallest latLonAltBox that contains the LineString. \see GeoDataLatLonAltBox */ const GeoDataLatLonAltBox& latLonAltBox() const override; /** * @brief Returns the length of LineString across a sphere starting from a coordinate in LineString * This method can be used as an approximation for distances along LineStrings. * The unit used for the resulting length matches the unit of the planet * radius. * @param planetRadius radius of the sphere * @param offset position of coordinate within LineString */ virtual qreal length( qreal planetRadius, int offset = 0 ) const; /*! \brief Provides a more generic representation of the LineString. The LineString is normalized, and pole corrected. Deprecation Warning: This method will likely be removed from the public API. */ virtual GeoDataLineString toRangeCorrected() const; /*! \brief The line string with nodes that have proper longitude/latitude ranges. \return A LineString that resembles the original linestring with nodes that have longitude values between -180 and +180 deg and that feature latitude values between -90 and +90 deg. Deprecation Warning: This method will likely be removed from the public API. */ virtual GeoDataLineString toNormalized() const; /*! \brief The line string with more generic pole values. \return A LineString that resembles the original linestring. Nodes that represent one of the poles are duplicated to allow for a better visualization of flat projections. Deprecation Warning: This method will likely be removed from the public API. */ virtual GeoDataLineString toPoleCorrected() const; /*! \brief The line string corrected for date line crossing. \return A set of LineStrings that don't cross the dateline and which resemble the original linestring. Deprecation Warning: This method will likely be removed from the public API. */ virtual QVector toDateLineCorrected() const; // "Reimplementation" of QVector API /*! \brief Returns whether the LineString has no nodes at all. \return true if there are no nodes inside the line string. */ bool isEmpty() const; /*! \brief Returns the number of nodes in a LineString. */ int size() const; /*! \brief Returns a reference to the coordinates of a node at a given position. This method detaches the returned coordinate object from the line string. */ GeoDataCoordinates& at( int pos ); /*! \brief Returns a reference to the coordinates of a node at a given position. This method does not detach the returned coordinate object from the line string. */ const GeoDataCoordinates& at( int pos ) const; /*! \brief Returns a reference to the coordinates of a node at a given position. This method detaches the returned coordinate object from the line string. */ GeoDataCoordinates& operator[]( int pos ); /** Returns a sub-string which contains elements from this vector, starting at position pos. If length is -1 (the default), all elements after pos are included; otherwise length elements (or all remaining elements if there are less than length elements) are included. */ GeoDataLineString mid(int pos, int length = -1) const; /*! \brief Returns a reference to the coordinates of a node at a given position. This method does not detach the returned coordinate object from the line string. */ const GeoDataCoordinates& operator[]( int pos ) const; /*! \brief Returns a reference to the first node in the LineString. This method detaches the returned coordinate object from the line string. */ GeoDataCoordinates& first(); /*! \brief Returns a reference to the first node in the LineString. This method does not detach the returned coordinate object from the line string. */ const GeoDataCoordinates& first() const; /*! \brief Returns a reference to the last node in the LineString. This method detaches the returned coordinate object from the line string. */ GeoDataCoordinates& last(); /*! \brief Returns a reference to the last node in the LineString. This method does not detach the returned coordinate object from the line string. */ const GeoDataCoordinates& last() const; /*! \brief Inserts a new node at the given index. */ void insert( int index, const GeoDataCoordinates& value ); /*! \brief Attempts to allocate memory for at least \a size coordinates. */ void reserve(int size); /*! \brief Appends a given geodesic position as a new node to the LineString. */ void append ( const GeoDataCoordinates& value ); /*! \brief Appends a given geodesic position as new nodes to the LineString. */ void append(const QVector& values); /*! \brief Appends a given geodesic position as a new node to the LineString. */ GeoDataLineString& operator << ( const GeoDataCoordinates& value ); /*! \brief Appends a given LineString to the end of the LineString. */ GeoDataLineString& operator << ( const GeoDataLineString& lineString ); /*! \brief Returns true/false depending on whether this and other are/are not equal. */ bool operator==( const GeoDataLineString &other ) const; bool operator!=( const GeoDataLineString &other ) const; /*! \brief Returns an iterator that points to the begin of the LineString. */ QVector::Iterator begin(); QVector::ConstIterator begin() const; /*! \brief Returns an iterator that points to the end of the LineString. */ QVector::Iterator end(); QVector::ConstIterator end() const; /*! \brief Returns a const iterator that points to the begin of the LineString. */ QVector::ConstIterator constBegin() const; /*! \brief Returns a const iterator that points to the end of the LineString. */ QVector::ConstIterator constEnd() const; /*! \brief Destroys all nodes in a LineString. */ void clear(); /*! \brief Removes the node at the given position and returns it. */ QVector::Iterator erase ( const QVector::Iterator& position ); /*! \brief Removes the nodes within the given range and returns them. */ QVector::Iterator erase ( const QVector::Iterator& begin, const QVector::Iterator& end ); /*! \brief Removes the node at the given position and destroys it. */ void remove ( int i ); /*! \brief Returns a linestring with detail values assigned to each node. */ GeoDataLineString optimized() const; // Serialization /*! \brief Serialize the LineString to a stream. \param stream the stream. */ void pack( QDataStream& stream ) const override; /*! \brief Unserialize the LineString from a stream. \param stream the stream. */ void unpack( QDataStream& stream ) override; protected: explicit GeoDataLineString(GeoDataLineStringPrivate* priv); private: Q_DECLARE_PRIVATE(GeoDataLineString) }; } Q_DECLARE_METATYPE( Marble::GeoDataLineString ) #endif diff --git a/src/lib/marble/geodata/data/GeoDataPoint.h b/src/lib/marble/geodata/data/GeoDataPoint.h index a85378b68..a6dd394f4 100644 --- a/src/lib/marble/geodata/data/GeoDataPoint.h +++ b/src/lib/marble/geodata/data/GeoDataPoint.h @@ -1,103 +1,103 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2006-2007 Torsten Rahn // Copyright 2007 Inge Wallin // Copyright 2008 Patrick Spendrin // #ifndef MARBLE_GEODATAPOINT_H #define MARBLE_GEODATAPOINT_H #include #include #include #include "geodata_export.h" #include "GeoDataGeometry.h" #include "GeoDataCoordinates.h" namespace Marble { class GeoDataPointPrivate; /** * @short A Geometry object representing a 3d point * * GeoDataPoint is the GeoDataGeometry class representing a single three * dimensional point. It reflects the Point tag of KML spec and can be contained * in objects holding GeoDataGeometry objects. * Nevertheless GeoDataPoint shouldn't be used if you just want to store * 3d coordinates of a point that doesn't need to be inherited from GeoDataGeometry * In that case use GeoDataCoordinates instead which has nearly the same features * and is much more light weight. * Please consider this especially if you expect to have a high * amount of points e.g. for line strings, linear rings and polygons. * @see GeoDataCoordinates * @see GeoDataGeometry */ class GEODATA_EXPORT GeoDataPoint : public GeoDataGeometry { public: - typedef GeoDataCoordinates::Notation Notation; - typedef GeoDataCoordinates::Unit Unit; + using Notation = GeoDataCoordinates::Notation; + using Unit = GeoDataCoordinates::Unit; GeoDataPoint( const GeoDataPoint& other ); explicit GeoDataPoint( const GeoDataCoordinates& other ); GeoDataPoint(); /** * @brief create a geopoint from longitude and latitude * @param _lon longitude * @param _lat latitude * @param alt altitude (default: 0) * @param _unit units that lon and lat get measured in * (default for Radian: north pole at pi/2, southpole at -pi/2) */ GeoDataPoint( qreal lon, qreal lat, qreal alt = 0, GeoDataPoint::Unit _unit = GeoDataCoordinates::Radian ); ~GeoDataPoint() override; EnumGeometryId geometryId() const override; GeoDataGeometry *copy() const override; bool operator==( const GeoDataPoint &other ) const; bool operator!=( const GeoDataPoint &other ) const; void setCoordinates( const GeoDataCoordinates &coordinates ); const GeoDataCoordinates& coordinates() const; /// Provides type information for downcasting a GeoData const char* nodeType() const override; // Type definitions - typedef QVector Vector; + using Vector = QVector; // Serialize the Placemark to @p stream void pack( QDataStream& stream ) const override; // Unserialize the Placemark from @p stream void unpack( QDataStream& stream ) override; virtual void detach(); private: Q_DECLARE_PRIVATE(GeoDataPoint) }; } Q_DECLARE_METATYPE( Marble::GeoDataPoint ) #endif diff --git a/src/lib/marble/geodata/data/GeoDataStyle.h b/src/lib/marble/geodata/data/GeoDataStyle.h index 4560305c9..17bc81acd 100644 --- a/src/lib/marble/geodata/data/GeoDataStyle.h +++ b/src/lib/marble/geodata/data/GeoDataStyle.h @@ -1,137 +1,137 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2007 Murad Tagirov // Copyright 2007 Inge Wallin // #ifndef MARBLE_GEODATASTYLE_H #define MARBLE_GEODATASTYLE_H #include "GeoDataStyleSelector.h" #include "geodata_export.h" #include #include class QFont; class QColor; namespace Marble { class GeoDataBalloonStyle; class GeoDataIconStyle; class GeoDataLabelStyle; class GeoDataLineStyle; class GeoDataListStyle; class GeoDataPolyStyle; class GeoDataStylePrivate; /** * @short an addressable style group * * A GeoDataStyle defines an addressable style group that can be * referenced by GeoDataStyleMaps and GeoDataFeatures. GeoDataStyles * affect how Geometry is presented in the 3D viewer (not yet * implemented) and how Features appear. Shared styles are collected * in a GeoDataDocument and must have an id defined for them so that * they can be referenced by the individual Features that use them. * * @see GeoDataIconStyle * @see GeoDataLabelStyle * @see GeoDataLineStyle * @see GeoDataPolyStyle * @see GeoDataBalloonStyle * @see GeoDataListStyle */ class GEODATA_EXPORT GeoDataStyle : public GeoDataStyleSelector { public: - typedef QSharedPointer Ptr; - typedef QSharedPointer ConstPtr; + using Ptr = QSharedPointer; + using ConstPtr = QSharedPointer; /// Construct a default style GeoDataStyle(); GeoDataStyle( const GeoDataStyle& other ); /** * @brief Construct a new style * @param icon used to construct the icon style * @param font used to construct the label styles * @param color used to construct the label styles */ GeoDataStyle( const QString& iconPath, const QFont &font, const QColor &color ); ~GeoDataStyle() override; /// Provides type information for downcasting a GeoNode const char* nodeType() const override; /// set the icon style void setIconStyle( const GeoDataIconStyle& style ); /// Return the icon style of this style GeoDataIconStyle& iconStyle(); const GeoDataIconStyle& iconStyle() const; /// set the label style void setLabelStyle( const GeoDataLabelStyle& style ); /// Return the label style of this style GeoDataLabelStyle& labelStyle(); const GeoDataLabelStyle& labelStyle() const; /// set the line style void setLineStyle( const GeoDataLineStyle& style ); /// Return the label style of this style GeoDataLineStyle& lineStyle(); const GeoDataLineStyle& lineStyle() const; /// set the poly style void setPolyStyle( const GeoDataPolyStyle& style ); /// Return the label style of this style GeoDataPolyStyle& polyStyle(); const GeoDataPolyStyle& polyStyle() const; /// set the balloon style void setBalloonStyle( const GeoDataBalloonStyle& style ); /// Return the balloon style of this style GeoDataBalloonStyle& balloonStyle(); const GeoDataBalloonStyle& balloonStyle() const; /// set the list style void setListStyle( const GeoDataListStyle& style ); /// Return the list style of this style GeoDataListStyle& listStyle(); const GeoDataListStyle& listStyle() const; /** * @brief assignment operator * @param other the GeoDataStyle that gets duplicated */ GeoDataStyle& operator=( const GeoDataStyle& other ); bool operator==( const GeoDataStyle &other ) const; bool operator!=( const GeoDataStyle &other ) const; /** * @brief Serialize the style to a stream * @param stream the stream */ void pack( QDataStream& stream ) const override; /** * @brief Unserialize the style from a stream * @param stream the stream */ void unpack( QDataStream& stream ) override; private: GeoDataStylePrivate * const d; }; } Q_DECLARE_METATYPE( Marble::GeoDataStyle* ) Q_DECLARE_METATYPE( const Marble::GeoDataStyle* ) #endif diff --git a/src/lib/marble/geodata/parser/GeoParser.h b/src/lib/marble/geodata/parser/GeoParser.h index 913ef8bc8..1e86ca9d4 100644 --- a/src/lib/marble/geodata/parser/GeoParser.h +++ b/src/lib/marble/geodata/parser/GeoParser.h @@ -1,144 +1,144 @@ /* Copyright (C) 2008 Nikolas Zimmermann This file is part of the KDE project This library is free software you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MARBLE_GEOPARSER_H #define MARBLE_GEOPARSER_H #include #include #include #include "geodata_export.h" namespace Marble { -typedef int GeoDataGenericSourceType; +using GeoDataGenericSourceType = int; class GeoDocument; class GeoNode; class GeoStackItem; class GEODATA_EXPORT GeoParser : public QXmlStreamReader { public: typedef QPair QualifiedName; // Tag Name & Namespace pair explicit GeoParser( GeoDataGenericSourceType sourceType ); virtual ~GeoParser(); /** * @brief Main API for reading the XML document. * This is the only method that is necessary to call to start the GeoParser. * To retrieve the resulting data see @see releaseDocument() and * @see releaseModel() */ bool read( QIODevice* ); /** * @brief retrieve the parsed document and reset the parser * If parsing was successful, retrieve the resulting document * and set the contained m_document pointer to 0. */ GeoDocument* releaseDocument(); GeoDocument* activeDocument() { return m_document; } // Used by tag handlers, to be overridden by GeoDataParser/GeoSceneParser virtual bool isValidElement( const QString& tagName ) const; // Used by tag handlers, to access a parent element's associated GeoStackItem GeoStackItem parentElement( unsigned int depth = 0 ) const; // Used by tag handlers, to emit a warning while parsing void raiseWarning( const QString& ); // Used by tag handlers, to retrieve the value for an attribute of the currently parsed element QString attribute( const char* attributeName ) const; protected: /** * This method is intended to check if the current element being served by * the GeoParser is a valid Document Root element. This method is to be * implemented by GeoDataParser/GeoSceneParser and must check based on the * current XML Document type, e.g. KML, GPX etc. * @return @c true if the element is a valid document root. */ virtual bool isValidRootElement() = 0; virtual GeoDocument* createDocument() const = 0; protected: GeoDocument* m_document; GeoDataGenericSourceType m_source; private: void parseDocument(); QStack m_nodeStack; }; class GeoStackItem { public: GeoStackItem() : m_qualifiedName(), m_node( nullptr ) { } GeoStackItem( const GeoParser::QualifiedName& qualifiedName, GeoNode* node ) : m_qualifiedName( qualifiedName ), m_node( node ) { } // Fast path for tag handlers bool represents( const char* tagName ) const { return m_node && tagName == m_qualifiedName.first; } // Helper for tag handlers. Does NOT guard against miscasting. Use with care. template T* nodeAs() { Q_ASSERT( dynamic_cast( m_node ) != nullptr ); return static_cast(m_node); } template bool is() const { return nullptr != dynamic_cast(m_node); } GeoParser::QualifiedName qualifiedName() const { return m_qualifiedName; } GeoNode* associatedNode() const { return m_node; } private: friend class GeoParser; void assignNode( GeoNode* node ) { m_node = node; } GeoParser::QualifiedName m_qualifiedName; GeoNode* m_node; }; } #endif diff --git a/src/lib/marble/kbihash_p.h b/src/lib/marble/kbihash_p.h index fc09dfcf9..a4dff96d5 100644 --- a/src/lib/marble/kbihash_p.h +++ b/src/lib/marble/kbihash_p.h @@ -1,575 +1,575 @@ /* Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net, author Stephen Kelly This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KBIHASH_P_H #define KBIHASH_P_H #include #include #include template class KBiAssociativeContainer; template QDebug operator<<(QDebug out, const KBiAssociativeContainer &container); template QDataStream &operator<<(QDataStream &out, const KBiAssociativeContainer &container); template QDataStream &operator>>(QDataStream &in, KBiAssociativeContainer &container); template class KBiAssociativeContainer { // We need to convert from a QHash::iterator or QMap::iterator // to a KBiAssociativeContainer::iterator (left or right) // Do do that we use this implicit ctor. We partially specialize // it for QHash and QMap types. // Our iterator inherits from this struct to get the implicit ctor, // and this struct must inherit from the QHash or QMap iterator. template struct _iterator_impl_ctor : public Container::iterator { _iterator_impl_ctor(typename Container::iterator it); }; template struct _iterator_impl_ctor, T, U> : public QHash::iterator { /* implicit */ _iterator_impl_ctor(const typename QHash::iterator it) // Using internals here because I was too lazy to write my own iterator. #if QT_VERSION < 0x050000 : QHash::iterator(reinterpret_cast(static_cast *>(it))) #else : QHash::iterator(it) #endif { } }; template struct _iterator_impl_ctor, T, U> : public QMap::iterator { /* implicit */ _iterator_impl_ctor(const typename QMap::iterator it) // Using internals here because I was too lazy to write my own iterator. #if QT_VERSION < 0x050000 : QMap::iterator(static_cast(it)) #else : QMap::iterator(it) #endif { } }; public: - typedef typename RightContainer::mapped_type left_type; - typedef typename LeftContainer::mapped_type right_type; + using left_type = typename QMap::mapped_type; + using right_type = typename QHash::mapped_type; template class _iterator : public _iterator_impl_ctor { public: explicit inline _iterator(void *data) : Container::iterator(data) {} /* implicit */ _iterator(const typename Container::iterator it) : _iterator_impl_ctor(it) { } inline const typename Container::mapped_type &value() const { return Container::iterator::value(); } inline const typename Container::mapped_type &operator*() const { return Container::iterator::operator*(); } inline const typename Container::mapped_type *operator->() const { return Container::iterator::operator->(); } private: #ifndef Q_CC_MSVC using Container::iterator::operator*; using Container::iterator::operator->; using Container::iterator::value; #endif }; - typedef _iterator left_iterator; - typedef typename LeftContainer::const_iterator left_const_iterator; - typedef _iterator right_iterator; - typedef typename RightContainer::const_iterator right_const_iterator; + using left_iterator = _iterator >; + using left_const_iterator = typename QHash::const_iterator; + using right_iterator = _iterator >; + using right_const_iterator = typename QMap::const_iterator; inline KBiAssociativeContainer() {} inline KBiAssociativeContainer(const KBiAssociativeContainer &other) { *this = other; } const KBiAssociativeContainer &operator=(const KBiAssociativeContainer &other) { _leftToRight = other._leftToRight; _rightToLeft = other._rightToLeft; return *this; } inline bool removeLeft(left_type t) { const right_type u = _leftToRight.take(t); return _rightToLeft.remove(u) != 0; } inline bool removeRight(right_type u) { const left_type t = _rightToLeft.take(u); return _leftToRight.remove(t) != 0; } inline right_type takeLeft(left_type t) { const right_type u = _leftToRight.take(t); _rightToLeft.remove(u); return u; } inline left_type takeRight(right_type u) { const left_type t = _rightToLeft.take(u); _leftToRight.remove(t); return t; } inline left_type rightToLeft(right_type u) const { return _rightToLeft.value(u); } inline right_type leftToRight(left_type t) const { return _leftToRight.value(t); } inline bool leftContains(left_type t) const { return _leftToRight.contains(t); } inline bool rightContains(right_type u) const { return _rightToLeft.contains(u); } inline int size() const { return _leftToRight.size(); } inline int count() const { return _leftToRight.count(); } inline int capacity() const { return _leftToRight.capacity(); } void reserve(int size) { _leftToRight.reserve(size); _rightToLeft.reserve(size); } inline void squeeze() { _leftToRight.squeeze(); _rightToLeft.squeeze(); } inline void detach() { _leftToRight.detach(); _rightToLeft.detach(); } inline bool isDetached() const { return _leftToRight.isDetached(); } inline void setSharable(bool sharable) { _leftToRight.setSharable(sharable); _rightToLeft.setSharable(sharable); } inline bool isSharedWith(const KBiAssociativeContainer &other) const { return _leftToRight.isSharedWith(other._leftToRight) && _rightToLeft.isSharedWith(other._leftToRight); } void clear() { _leftToRight.clear(); _rightToLeft.clear(); } QList leftValues() const { return _leftToRight.keys(); } QList rightValues() const { return _rightToLeft.keys(); } right_iterator eraseRight(right_iterator it) { Q_ASSERT(it != rightEnd()); _leftToRight.remove(it.value()); return _rightToLeft.erase(it); } left_iterator eraseLeft(left_iterator it) { Q_ASSERT(it != leftEnd()); _rightToLeft.remove(it.value()); return _leftToRight.erase(it); } left_iterator findLeft(left_type t) { return _leftToRight.find(t); } left_const_iterator findLeft(left_type t) const { return _leftToRight.find(t); } left_const_iterator constFindLeft(left_type t) const { return _leftToRight.constFind(t); } right_iterator findRight(right_type u) { return _rightToLeft.find(u); } right_const_iterator findRight(right_type u) const { return _rightToLeft.find(u); } right_const_iterator constFindRight(right_type u) const { return _rightToLeft.find(u); } left_iterator insert(left_type t, right_type u) { // biHash.insert(5, 7); // creates 5->7 in _leftToRight and 7->5 in _rightToLeft // biHash.insert(5, 9); // replaces 5->7 with 5->9 in _leftToRight and inserts 9->5 in _rightToLeft. // The 7->5 in _rightToLeft would be dangling, so we remove it before insertion. // This means we need to hash u and t up to twice each. Could probably be done better using QHashNode. if (_leftToRight.contains(t)) _rightToLeft.remove(_leftToRight.take(t)); if (_rightToLeft.contains(u)) _leftToRight.remove(_rightToLeft.take(u)); _rightToLeft.insert(u, t); return _leftToRight.insert(t, u); } KBiAssociativeContainer &intersect(const KBiAssociativeContainer &other) { typename KBiAssociativeContainer::left_iterator it = leftBegin(); while (it != leftEnd()) { if (!other.leftContains(it.key())) it = eraseLeft(it); else ++it; } return *this; } KBiAssociativeContainer &subtract(const KBiAssociativeContainer &other) { typename KBiAssociativeContainer::left_iterator it = leftBegin(); while (it != leftEnd()) { if (other._leftToRight.contains(it.key())) it = eraseLeft(it); else ++it; } return *this; } KBiAssociativeContainer &unite(const KBiAssociativeContainer &other) { typename LeftContainer::const_iterator it = other._leftToRight.constBegin(); const typename LeftContainer::const_iterator end = other._leftToRight.constEnd(); while (it != end) { const left_type key = it.key(); if (!_leftToRight.contains(key)) insert(key, it.value()); ++it; } return *this; } void updateRight(left_iterator it, right_type u) { Q_ASSERT(it != leftEnd()); const left_type key = it.key(); _rightToLeft.remove(_leftToRight.value(key)); _leftToRight[key] = u; _rightToLeft[u] = key; } void updateLeft(right_iterator it, left_type t) { Q_ASSERT(it != rightEnd()); const right_type key = it.key(); _leftToRight.remove(_rightToLeft.value(key)); _rightToLeft[key] = t; _leftToRight[t] = key; } inline bool isEmpty() const { return _leftToRight.isEmpty(); } const right_type operator[](const left_type &t) const { return _leftToRight.operator[](t); } bool operator==(const KBiAssociativeContainer &other) const { return _leftToRight.operator == (other._leftToRight); } bool operator!=(const KBiAssociativeContainer &other) const { return _leftToRight.operator != (other._leftToRight); } left_iterator toLeftIterator(right_iterator it) const { Q_ASSERT(it != rightEnd()); return _leftToRight.find(it.value()); } right_iterator toRightIterator(left_iterator it) const { Q_ASSERT(it != leftEnd()); return _rightToLeft.find(it.value()); } inline left_iterator leftBegin() { return _leftToRight.begin(); } inline left_iterator leftEnd() { return _leftToRight.end(); } inline left_const_iterator leftBegin() const { return _leftToRight.begin(); } inline left_const_iterator leftEnd() const { return _leftToRight.end(); } inline left_const_iterator leftConstBegin() const { return _leftToRight.constBegin(); } inline left_const_iterator leftConstEnd() const { return _leftToRight.constEnd(); } inline right_iterator rightBegin() { return _rightToLeft.begin(); } inline right_iterator rightEnd() { return _rightToLeft.end(); } inline right_const_iterator rightBegin() const { return _rightToLeft.begin(); } inline right_const_iterator rightEnd() const { return _rightToLeft.end(); } inline right_const_iterator rightConstBegin() const { return _rightToLeft.constBegin(); } inline right_const_iterator rightConstEnd() const { return _rightToLeft.constEnd(); } static KBiAssociativeContainer fromHash(const QHash &hash) { KBiAssociativeContainer container; typename QHash::const_iterator it = hash.constBegin(); const typename QHash::const_iterator end = hash.constEnd(); for ( ; it != end; ++it) container.insert(it.key(), it.value()); return container; } static KBiAssociativeContainer fromMap(const QMap &hash) { KBiAssociativeContainer container; typename QMap::const_iterator it = hash.constBegin(); const typename QMap::const_iterator end = hash.constEnd(); for ( ; it != end; ++it) container.insert(it.key(), it.value()); return container; } friend QDataStream &operator<< (QDataStream &out, const KBiAssociativeContainer &bihash); friend QDataStream &operator>> (QDataStream &in, KBiAssociativeContainer &biHash); friend QDebug operator<< (QDebug out, const KBiAssociativeContainer &biHash); protected: LeftContainer _leftToRight; RightContainer _rightToLeft; }; template QDataStream &operator<<(QDataStream &out, const KBiAssociativeContainer &container) { return out << container._leftToRight; } template QDataStream &operator>>(QDataStream &in, KBiAssociativeContainer &container) { LeftContainer leftToRight; in >> leftToRight; typename LeftContainer::const_iterator it = leftToRight.constBegin(); const typename LeftContainer::const_iterator end = leftToRight.constEnd(); for (; it != end; ++it) container.insert(it.key(), it.value()); return in; } template struct _containerType { operator const char *(); }; template struct _containerType, T, U> { operator const char *() { return "QHash"; } }; template struct _containerType, T, U> { operator const char *() { return "QMap"; } }; template static const char * containerType() { return _containerType(); } template QDebug operator<<(QDebug out, const KBiAssociativeContainer &container) { typename KBiAssociativeContainer::left_const_iterator it = container.leftConstBegin(); const typename KBiAssociativeContainer::left_const_iterator end = container.leftConstEnd(); out.nospace() << "KBiAssociativeContainer<" << containerType() << ", " << containerType() << ">" << "("; for (; it != end; ++it) out << "(" << it.key() << " <=> " << it.value() << ") "; out << ")"; return out; } /** * @brief KBiHash provides a bi-directional hash container * * @note This class is designed to make mapping easier in proxy model implementations. * * @todo Figure out whether to discard this and use boost::bimap instead, submit it Qt or keep it here and make more direct use of QHashNode. */ template struct KBiHash : public KBiAssociativeContainer, QHash > { KBiHash() : KBiAssociativeContainer, QHash > () { } KBiHash(const KBiAssociativeContainer, QHash > &container) : KBiAssociativeContainer, QHash > (container) { } }; template QDebug operator<<(QDebug out, const KBiHash &biHash) { typename KBiHash::left_const_iterator it = biHash.leftConstBegin(); const typename KBiHash::left_const_iterator end = biHash.leftConstEnd(); out.nospace() << "KBiHash("; for (; it != end; ++it) out << "(" << it.key() << " <=> " << it.value() << ") "; out << ")"; return out; } template struct KHash2Map : public KBiAssociativeContainer, QMap > { KHash2Map() : KBiAssociativeContainer, QMap > () { } KHash2Map(const KBiAssociativeContainer, QMap > &container) : KBiAssociativeContainer, QMap > (container) { } typename KBiAssociativeContainer, QMap >::right_iterator rightLowerBound(const U &key) { return this->_rightToLeft.lowerBound(key); } typename KBiAssociativeContainer, QMap >::right_const_iterator rightLowerBound(const U &key) const { return this->_rightToLeft.lowerBound(key); } typename KBiAssociativeContainer, QMap >::right_iterator rightUpperBound(const U &key) { return this->_rightToLeft.upperBound(key); } typename KBiAssociativeContainer, QMap >::right_const_iterator rightUpperBound(const U &key) const { return this->_rightToLeft.upperBound(key); } }; template QDebug operator<<(QDebug out, const KHash2Map &container) { typename KHash2Map::left_const_iterator it = container.leftConstBegin(); const typename KHash2Map::left_const_iterator end = container.leftConstEnd(); out.nospace() << "KHash2Map("; for (; it != end; ++it) out << "(" << it.key() << " <=> " << it.value() << ") "; out << ")"; return out; } #endif diff --git a/src/lib/marble/layers/GeometryLayer.cpp b/src/lib/marble/layers/GeometryLayer.cpp index f43b3e552..0c83996b3 100644 --- a/src/lib/marble/layers/GeometryLayer.cpp +++ b/src/lib/marble/layers/GeometryLayer.cpp @@ -1,715 +1,715 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2008-2009 Patrick Spendrin // Copyright 2010 Thibaut Gridel // Copyright 2011-2012 Bernhard Beschow // Copyright 2014 Gábor Péterffy // #include "GeometryLayer.h" // Marble #include "GeoDataLatLonAltBox.h" #include "GeoDataDocument.h" #include "GeoDataFolder.h" #include "GeoDataLineStyle.h" #include "GeoDataMultiTrack.h" #include "GeoDataObject.h" #include "GeoDataPlacemark.h" #include "GeoDataLinearRing.h" #include "GeoDataMultiGeometry.h" #include "GeoDataPolygon.h" #include "GeoDataBuilding.h" #include "GeoDataPolyStyle.h" #include "GeoDataStyle.h" #include "GeoDataIconStyle.h" #include "GeoDataStyleMap.h" #include "GeoDataTrack.h" #include "GeoDataFeature.h" #include "MarbleDebug.h" #include "GeoPainter.h" #include "ViewportParams.h" #include "RenderState.h" #include "GeoGraphicsScene.h" #include "GeoGraphicsItem.h" #include "GeoLineStringGraphicsItem.h" #include "GeoPolygonGraphicsItem.h" #include "GeoTrackGraphicsItem.h" #include "GeoDataPhotoOverlay.h" #include "GeoDataScreenOverlay.h" #include "GeoPhotoGraphicsItem.h" #include "ScreenOverlayGraphicsItem.h" #include "TileId.h" #include "MarbleGraphicsItem.h" #include "MarblePlacemarkModel.h" #include "GeoDataTreeModel.h" #include #include "StyleBuilder.h" #include "AbstractGeoPolygonGraphicsItem.h" #include "GeoLineStringGraphicsItem.h" #include "GeoDataRelation.h" // Qt #include #include #include namespace Marble { class GeometryLayerPrivate { public: - typedef QVector OsmLineStringItems; - typedef QSet Relations; + using OsmLineStringItems = QVector; + using Relations = QSet; typedef QHash FeatureRelationHash; - typedef QVector GeoGraphicItems; + using GeoGraphicItems = QVector; struct PaintFragments { // Three lists for different z values // A z value of 0 is default and used by the majority of items, so sorting // can be avoided for it QVector negative; // subways QVector null; // areas and roads QVector positive; // buildings }; explicit GeometryLayerPrivate(const QAbstractItemModel *model, const StyleBuilder *styleBuilder); void createGraphicsItems(const GeoDataObject *object); void createGraphicsItems(const GeoDataObject *object, FeatureRelationHash &relations); void createGraphicsItemFromGeometry(const GeoDataGeometry *object, const GeoDataPlacemark *placemark, const Relations &relations); void createGraphicsItemFromOverlay(const GeoDataOverlay *overlay); void removeGraphicsItems(const GeoDataFeature *feature); void updateTiledLineStrings(const GeoDataPlacemark *placemark, GeoLineStringGraphicsItem* lineStringItem); static void updateTiledLineStrings(OsmLineStringItems &lineStringItems); void clearCache(); bool showRelation(const GeoDataRelation* relation) const; void updateRelationVisibility(); const QAbstractItemModel *const m_model; const StyleBuilder *const m_styleBuilder; GeoGraphicsScene m_scene; QString m_runtimeTrace; QList m_screenOverlays; QHash m_osmLineStringItems; int m_tileLevel; GeoGraphicsItem* m_lastFeatureAt; bool m_dirty; int m_cachedItemCount; QHash m_cachedPaintFragments; typedef QPair LayerItem; QList m_cachedDefaultLayer; QDateTime m_cachedDateTime; GeoDataLatLonBox m_cachedLatLonBox; QSet m_highlightedRouteRelations; GeoDataRelation::RelationTypes m_visibleRelationTypes; bool m_levelTagDebugModeEnabled; int m_debugLevelTag; }; GeometryLayerPrivate::GeometryLayerPrivate(const QAbstractItemModel *model, const StyleBuilder *styleBuilder) : m_model(model), m_styleBuilder(styleBuilder), m_tileLevel(0), m_lastFeatureAt(nullptr), m_dirty(true), m_cachedItemCount(0), m_visibleRelationTypes(GeoDataRelation::RouteFerry), m_levelTagDebugModeEnabled(false), m_debugLevelTag(0) { } void GeometryLayerPrivate::createGraphicsItems(const GeoDataObject *object) { FeatureRelationHash noRelations; createGraphicsItems(object, noRelations); } GeometryLayer::GeometryLayer(const QAbstractItemModel *model, const StyleBuilder *styleBuilder) : d(new GeometryLayerPrivate(model, styleBuilder)) { const GeoDataObject *object = static_cast(d->m_model->index(0, 0, QModelIndex()).internalPointer()); if (object && object->parent()) { d->createGraphicsItems(object->parent()); } connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(resetCacheData())); connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(addPlacemarks(QModelIndex, int, int))); connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), this, SLOT(removePlacemarks(QModelIndex, int, int))); connect(model, SIGNAL(modelReset()), this, SLOT(resetCacheData())); connect(this, SIGNAL(highlightedPlacemarksChanged(QVector)), &d->m_scene, SLOT(applyHighlight(QVector))); connect(&d->m_scene, SIGNAL(repaintNeeded()), this, SIGNAL(repaintNeeded())); } GeometryLayer::~GeometryLayer() { delete d; } QStringList GeometryLayer::renderPosition() const { return QStringList(QStringLiteral("HOVERS_ABOVE_SURFACE")); } bool GeometryLayer::render(GeoPainter *painter, ViewportParams *viewport, const QString& renderPos, GeoSceneLayer * layer) { Q_UNUSED(renderPos) Q_UNUSED(layer) painter->save(); auto const & box = viewport->viewLatLonAltBox(); bool isEqual = GeoDataLatLonBox::fuzzyCompare(d->m_cachedLatLonBox, box, 0.05); if (d->m_cachedLatLonBox.isEmpty() || !isEqual) { d->m_dirty = true; } // update the items cache at least every second since the last request auto const now = QDateTime::currentDateTime(); if (!d->m_cachedDateTime.isValid() || d->m_cachedDateTime.msecsTo(now) > 1000) { d->m_dirty = true; } if (d->m_dirty) { d->m_dirty = false; const int maxZoomLevel = qMin(d->m_tileLevel, d->m_styleBuilder->maximumZoomLevel()); auto const items = d->m_scene.items(box, maxZoomLevel);; d->m_cachedLatLonBox = box; d->m_cachedDateTime = now; d->m_cachedItemCount = items.size(); d->m_cachedDefaultLayer.clear(); d->m_cachedPaintFragments.clear(); QHash paintFragments; QSet const knownLayers = QSet::fromList(d->m_styleBuilder->renderOrder()); for (GeoGraphicsItem* item: items) { QStringList paintLayers = item->paintLayers(); if (paintLayers.isEmpty()) { mDebug() << item << " provides no paint layers, so I force one onto it."; paintLayers << QString(); } for (const auto &layer: paintLayers) { if (knownLayers.contains(layer)) { GeometryLayerPrivate::PaintFragments &fragments = paintFragments[layer]; double const zValue = item->zValue(); // assign subway stations if (zValue == 0.0) { fragments.null << item; // assign areas and streets } else if (zValue < 0.0) { fragments.negative << item; // assign buildings } else { fragments.positive << item; } } else { // assign symbols d->m_cachedDefaultLayer << GeometryLayerPrivate::LayerItem(layer, item); static QSet missingLayers; if (!missingLayers.contains(layer)) { mDebug() << "Missing layer " << layer << ", in render order, will render it on top"; missingLayers << layer; } } } } // Sort each fragment by z-level for (const QString &layer: d->m_styleBuilder->renderOrder()) { GeometryLayerPrivate::PaintFragments & layerItems = paintFragments[layer]; std::sort(layerItems.negative.begin(), layerItems.negative.end(), GeoGraphicsItem::zValueLessThan); // The idea here is that layerItems.null has most items and does not need to be sorted by z-value // since they are all equal (=0). We do sort them by style pointer though for batch rendering std::sort(layerItems.null.begin(), layerItems.null.end(), GeoGraphicsItem::styleLessThan); std::sort(layerItems.positive.begin(), layerItems.positive.end(), GeoGraphicsItem::zValueAndStyleLessThan); auto const count = layerItems.negative.size() + layerItems.null.size() + layerItems.positive.size(); d->m_cachedPaintFragments[layer].reserve(count); d->m_cachedPaintFragments[layer] << layerItems.negative; d->m_cachedPaintFragments[layer] << layerItems.null; d->m_cachedPaintFragments[layer] << layerItems.positive; } } for (const QString &layer: d->m_styleBuilder->renderOrder()) { auto & layerItems = d->m_cachedPaintFragments[layer]; AbstractGeoPolygonGraphicsItem::s_previousStyle = nullptr; GeoLineStringGraphicsItem::s_previousStyle = nullptr; for (auto item: layerItems) { if (d->m_levelTagDebugModeEnabled) { if (const auto placemark = geodata_cast(item->feature())) { if (placemark->hasOsmData()) { QHash::const_iterator tagIter = placemark->osmData().findTag(QStringLiteral("level")); if (tagIter != placemark->osmData().tagsEnd()) { const int val = tagIter.value().toInt(); if (val != d->m_debugLevelTag) { continue; } } } } } item->paint(painter, viewport, layer, d->m_tileLevel); } } for (const auto & item: d->m_cachedDefaultLayer) { item.second->paint(painter, viewport, item.first, d->m_tileLevel); } for (ScreenOverlayGraphicsItem* item: d->m_screenOverlays) { item->paintEvent(painter, viewport); } painter->restore(); d->m_runtimeTrace = QStringLiteral("Geometries: %1 Zoom: %2") .arg(d->m_cachedItemCount) .arg(d->m_tileLevel); return true; } RenderState GeometryLayer::renderState() const { return RenderState(QStringLiteral("GeoGraphicsScene")); } QString GeometryLayer::runtimeTrace() const { return d->m_runtimeTrace; } bool GeometryLayer::hasFeatureAt(const QPoint &curpos, const ViewportParams *viewport) { if (d->m_lastFeatureAt && d->m_lastFeatureAt->contains(curpos, viewport)) { return true; } auto const renderOrder = d->m_styleBuilder->renderOrder(); for (int i = renderOrder.size() - 1; i >= 0; --i) { auto & layerItems = d->m_cachedPaintFragments[renderOrder[i]]; for (auto item : layerItems) { if (item->contains(curpos, viewport)) { d->m_lastFeatureAt = item; return true; } } } return false; } void GeometryLayerPrivate::createGraphicsItems(const GeoDataObject *object, FeatureRelationHash &relations) { clearCache(); if (auto document = geodata_cast(object)) { for (auto feature: document->featureList()) { if (auto relation = geodata_cast(feature)) { relation->setVisible(showRelation(relation)); for (auto member: relation->members()) { relations[member] << relation; } } } } if (auto placemark = geodata_cast(object)) { createGraphicsItemFromGeometry(placemark->geometry(), placemark, relations.value(placemark)); } else if (const GeoDataOverlay* overlay = dynamic_cast(object)) { createGraphicsItemFromOverlay(overlay); } // parse all child objects of the container if (const GeoDataContainer *container = dynamic_cast(object)) { int rowCount = container->size(); for (int row = 0; row < rowCount; ++row) { createGraphicsItems(container->child(row), relations); } } } void GeometryLayerPrivate::updateTiledLineStrings(const GeoDataPlacemark* placemark, GeoLineStringGraphicsItem* lineStringItem) { if (!placemark->hasOsmData()) { return; } qint64 const osmId = placemark->osmData().oid(); if (osmId <= 0) { return; } auto & lineStringItems = m_osmLineStringItems[osmId]; lineStringItems << lineStringItem; updateTiledLineStrings(lineStringItems); } void GeometryLayerPrivate::updateTiledLineStrings(OsmLineStringItems &lineStringItems) { GeoDataLineString merged; if (lineStringItems.size() > 1) { QVector lineStrings; for (auto item : lineStringItems) { lineStrings << item->lineString(); } merged = GeoLineStringGraphicsItem::merge(lineStrings); } // If merging failed, reset all. Otherwise only the first one // gets the merge result and becomes visible. bool visible = true; for (auto item : lineStringItems) { item->setVisible(visible); if (visible) { item->setMergedLineString(merged); visible = merged.isEmpty(); } } } void GeometryLayerPrivate::clearCache() { m_lastFeatureAt = nullptr; m_dirty = true; m_cachedDateTime = QDateTime(); m_cachedItemCount = 0; m_cachedPaintFragments.clear(); m_cachedDefaultLayer.clear(); m_cachedLatLonBox = GeoDataLatLonBox(); } inline bool GeometryLayerPrivate::showRelation(const GeoDataRelation *relation) const { return (m_visibleRelationTypes.testFlag(relation->relationType()) || m_highlightedRouteRelations.contains(relation->osmData().oid())); } void GeometryLayerPrivate::updateRelationVisibility() { for (int i = 0; i < m_model->rowCount(); ++i) { QVariant const data = m_model->data(m_model->index(i, 0), MarblePlacemarkModel::ObjectPointerRole); GeoDataObject *object = qvariant_cast (data); if (auto doc = geodata_cast(object)) { for (auto feature: doc->featureList()) { if (auto relation = geodata_cast(feature)) { relation->setVisible(showRelation(relation)); } } } } m_scene.resetStyle(); } void GeometryLayerPrivate::createGraphicsItemFromGeometry(const GeoDataGeometry* object, const GeoDataPlacemark *placemark, const Relations &relations) { if (!placemark->isGloballyVisible()) { return; // Reconsider this when visibility can be changed dynamically } GeoGraphicsItem *item = nullptr; if (const auto line = geodata_cast(object)) { auto lineStringItem = new GeoLineStringGraphicsItem(placemark, line); item = lineStringItem; updateTiledLineStrings(placemark, lineStringItem); } else if (const auto ring = geodata_cast(object)) { item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, ring); } else if (const auto poly = geodata_cast(object)) { item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, poly); if (item->zValue() == 0) { item->setZValue(poly->renderOrder()); } } else if (const auto building = geodata_cast(object)) { item = GeoPolygonGraphicsItem::createGraphicsItem(placemark, building); } else if (const auto multigeo = geodata_cast(object)) { int rowCount = multigeo->size(); for (int row = 0; row < rowCount; ++row) { createGraphicsItemFromGeometry(multigeo->child(row), placemark, relations); } } else if (const auto multitrack = geodata_cast(object)) { int rowCount = multitrack->size(); for (int row = 0; row < rowCount; ++row) { createGraphicsItemFromGeometry(multitrack->child(row), placemark, relations); } } else if (const auto track = geodata_cast(object)) { item = new GeoTrackGraphicsItem(placemark, track); } if (!item) { return; } item->setRelations(relations); item->setStyleBuilder(m_styleBuilder); item->setVisible(item->visible() && placemark->isGloballyVisible()); item->setMinZoomLevel(m_styleBuilder->minimumZoomLevel(*placemark)); m_scene.addItem(item); } void GeometryLayerPrivate::createGraphicsItemFromOverlay(const GeoDataOverlay *overlay) { if (!overlay->isGloballyVisible()) { return; // Reconsider this when visibility can be changed dynamically } GeoGraphicsItem* item = nullptr; if (const auto photoOverlay = geodata_cast(overlay)) { GeoPhotoGraphicsItem *photoItem = new GeoPhotoGraphicsItem(overlay); photoItem->setPoint(photoOverlay->point()); item = photoItem; } else if (const auto screenOverlay = geodata_cast(overlay)) { ScreenOverlayGraphicsItem *screenItem = new ScreenOverlayGraphicsItem(screenOverlay); m_screenOverlays.push_back(screenItem); } if (item) { item->setStyleBuilder(m_styleBuilder); item->setVisible(overlay->isGloballyVisible()); m_scene.addItem(item); } } void GeometryLayerPrivate::removeGraphicsItems(const GeoDataFeature *feature) { clearCache(); if (const auto placemark = geodata_cast(feature)) { if (placemark->isGloballyVisible() && geodata_cast(placemark->geometry()) && placemark->hasOsmData() && placemark->osmData().oid() > 0) { auto & items = m_osmLineStringItems[placemark->osmData().oid()]; bool removed = false; for (auto item : items) { if (item->feature() == feature) { items.removeOne(item); removed = true; break; } } Q_ASSERT(removed); updateTiledLineStrings(items); } m_scene.removeItem(feature); } else if (const auto container = dynamic_cast(feature)) { for (const GeoDataFeature *child: container->featureList()) { removeGraphicsItems(child); } } else if (geodata_cast(feature)) { for (ScreenOverlayGraphicsItem *item: m_screenOverlays) { if (item->screenOverlay() == feature) { m_screenOverlays.removeAll(item); } } } } void GeometryLayer::addPlacemarks(const QModelIndex& parent, int first, int last) { Q_ASSERT(first < d->m_model->rowCount(parent)); Q_ASSERT(last < d->m_model->rowCount(parent)); for (int i = first; i <= last; ++i) { QModelIndex index = d->m_model->index(i, 0, parent); Q_ASSERT(index.isValid()); const GeoDataObject *object = qvariant_cast(index.data(MarblePlacemarkModel::ObjectPointerRole)); Q_ASSERT(object); d->createGraphicsItems(object); } emit repaintNeeded(); } void GeometryLayer::removePlacemarks(const QModelIndex& parent, int first, int last) { Q_ASSERT(last < d->m_model->rowCount(parent)); bool isRepaintNeeded = false; for (int i = first; i <= last; ++i) { QModelIndex index = d->m_model->index(i, 0, parent); Q_ASSERT(index.isValid()); const GeoDataObject *object = qvariant_cast(index.data(MarblePlacemarkModel::ObjectPointerRole)); const GeoDataFeature *feature = dynamic_cast(object); if (feature != nullptr) { d->removeGraphicsItems(feature); isRepaintNeeded = true; } } if (isRepaintNeeded) { emit repaintNeeded(); } } void GeometryLayer::resetCacheData() { d->clearCache(); d->m_scene.clear(); qDeleteAll(d->m_screenOverlays); d->m_screenOverlays.clear(); d->m_osmLineStringItems.clear(); const GeoDataObject *object = static_cast(d->m_model->index(0, 0, QModelIndex()).internalPointer()); if (object && object->parent()) { d->createGraphicsItems(object->parent()); } emit repaintNeeded(); } void GeometryLayer::setTileLevel(int tileLevel) { d->m_tileLevel = tileLevel; } QVector GeometryLayer::whichFeatureAt(const QPoint &curpos, const ViewportParams *viewport) { QVector result; auto const renderOrder = d->m_styleBuilder->renderOrder(); QString const label = QStringLiteral("/label"); QSet checked; for (int i = renderOrder.size()-1; i >= 0; --i) { if (renderOrder[i].endsWith(label)) { continue; } auto & layerItems = d->m_cachedPaintFragments[renderOrder[i]]; for (auto j = layerItems.size()-1; j >= 0; --j) { auto const & layerItem = layerItems[j]; if (!checked.contains(layerItem)) { if (layerItem->contains(curpos, viewport)) { result << layerItem->feature(); } checked << layerItem; } } } return result; } void GeometryLayer::highlightRouteRelation(qint64 osmId, bool enabled) { if (enabled) { d->m_highlightedRouteRelations << osmId; } else { d->m_highlightedRouteRelations.remove(osmId); } d->updateRelationVisibility(); } void GeometryLayer::setVisibleRelationTypes(GeoDataRelation::RelationTypes relationTypes) { if (relationTypes != d->m_visibleRelationTypes) { d->m_visibleRelationTypes = relationTypes; d->updateRelationVisibility(); } } void GeometryLayer::handleHighlight(qreal lon, qreal lat, GeoDataCoordinates::Unit unit) { GeoDataCoordinates clickedPoint(lon, lat, 0, unit); QVector selectedPlacemarks; for (int i = 0; i < d->m_model->rowCount(); ++i) { QVariant const data = d->m_model->data(d->m_model->index(i, 0), MarblePlacemarkModel::ObjectPointerRole); GeoDataObject *object = qvariant_cast (data); Q_ASSERT(object); if (const auto doc = geodata_cast(object)) { bool isHighlight = false; for (const GeoDataStyleMap &styleMap: doc->styleMaps()) { if (styleMap.contains(QStringLiteral("highlight"))) { isHighlight = true; break; } } /* * If a document doesn't specify any highlight * styleId in its style maps then there is no need * to further check that document for placemarks * which have been clicked because we won't * highlight them. */ if (isHighlight) { QVector::Iterator iter = doc->begin(); QVector::Iterator const end = doc->end(); for (; iter != end; ++iter) { if (auto placemark = geodata_cast(*iter)) { GeoDataPolygon *polygon = dynamic_cast(placemark->geometry()); if (polygon && polygon->contains(clickedPoint)) { selectedPlacemarks.push_back(placemark); } if (auto linearRing = geodata_cast(placemark->geometry())) { if (linearRing->contains(clickedPoint)) { selectedPlacemarks.push_back(placemark); } } if (auto multiGeometry = geodata_cast(placemark->geometry())) { QVector::Iterator multiIter = multiGeometry->begin(); QVector::Iterator const multiEnd = multiGeometry->end(); for (; multiIter != multiEnd; ++multiIter) { GeoDataPolygon *poly = dynamic_cast(*multiIter); if (poly && poly->contains(clickedPoint)) { selectedPlacemarks.push_back(placemark); break; } if (auto linearRing = geodata_cast(*multiIter)) { if (linearRing->contains(clickedPoint)) { selectedPlacemarks.push_back(placemark); break; } } } } } } } } } emit highlightedPlacemarksChanged(selectedPlacemarks); } void GeometryLayer::setLevelTagDebugModeEnabled(bool enabled) { if (d->m_levelTagDebugModeEnabled != enabled) { d->m_levelTagDebugModeEnabled = enabled; emit repaintNeeded(); } } bool GeometryLayer::levelTagDebugModeEnabled() const { return d->m_levelTagDebugModeEnabled; } void GeometryLayer::setDebugLevelTag(int level) { if (d->m_debugLevelTag != level) { d->m_debugLevelTag = level; emit repaintNeeded(); } } int GeometryLayer::debugLevelTag() const { return d->m_debugLevelTag; } } #include "moc_GeometryLayer.cpp" diff --git a/src/lib/marble/layers/PlacemarkLayer.cpp b/src/lib/marble/layers/PlacemarkLayer.cpp index 4ae991856..4da00cc15 100644 --- a/src/lib/marble/layers/PlacemarkLayer.cpp +++ b/src/lib/marble/layers/PlacemarkLayer.cpp @@ -1,376 +1,376 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2006-2007 Torsten Rahn // Copyright 2007-2008 Inge Wallin // Copyright 2011-2012 Bernhard Beschow // #include "PlacemarkLayer.h" #include #include #include "MarbleDebug.h" #include "AbstractProjection.h" #include "GeoDataStyle.h" #include "GeoPainter.h" #include "GeoDataLatLonAltBox.h" #include "ViewportParams.h" #include "VisiblePlacemark.h" #include "RenderState.h" #include "osm/OsmPlacemarkData.h" #define BATCH_RENDERING using namespace Marble; bool PlacemarkLayer::m_useXWorkaround = false; PlacemarkLayer::PlacemarkLayer(QAbstractItemModel *placemarkModel, QItemSelectionModel *selectionModel, MarbleClock *clock, const StyleBuilder *styleBuilder, QObject *parent ) : QObject( parent ), m_layout( placemarkModel, selectionModel, clock, styleBuilder ), m_debugModeEnabled(false), m_levelTagDebugModeEnabled(false), m_tileLevel(0), m_debugLevelTag(0) { m_useXWorkaround = testXBug(); mDebug() << "Use workaround: " << ( m_useXWorkaround ? "1" : "0" ); connect( &m_layout, SIGNAL(repaintNeeded()), SIGNAL(repaintNeeded()) ); } PlacemarkLayer::~PlacemarkLayer() { } QStringList PlacemarkLayer::renderPosition() const { return QStringList(QStringLiteral("PLACEMARKS")); } qreal PlacemarkLayer::zValue() const { return 2.0; } bool PlacemarkLayer::render( GeoPainter *geoPainter, ViewportParams *viewport, const QString &renderPos, GeoSceneLayer *layer ) { Q_UNUSED( renderPos ) Q_UNUSED( layer ) QVector visiblePlacemarks = m_layout.generateLayout( viewport, m_tileLevel ); // draw placemarks less important first QVector::const_iterator visit = visiblePlacemarks.constEnd(); QVector::const_iterator itEnd = visiblePlacemarks.constBegin(); QPainter *const painter = geoPainter; bool const repeatableX = viewport->currentProjection()->repeatableX(); int const radius4 = 4 * viewport->radius(); #ifdef BATCH_RENDERING QHash hash; #endif while ( visit != itEnd ) { --visit; VisiblePlacemark *const mark = *visit; if (m_levelTagDebugModeEnabled) { if (mark->placemark()->hasOsmData()) { QHash::const_iterator tagIter = mark->placemark()->osmData().findTag(QStringLiteral("level")); if (tagIter != mark->placemark()->osmData().tagsEnd()) { const int val = tagIter.value().toInt(); if (val != m_debugLevelTag) { continue; } } } } // Intentionally converting positions from floating point to pixel aligned screen grid below QRect labelRect( mark->labelRect().toRect() ); QPoint symbolPos( mark->symbolPosition().toPoint()); // when the map is such zoomed out that a given place // appears many times, we draw one placemark at each if (repeatableX) { const int symbolX = symbolPos.x(); const int textX = labelRect.x(); for (int i = symbolX % radius4, width = viewport->width(); i <= width; i += radius4) { labelRect.moveLeft(i - symbolX + textX); symbolPos.setX(i); if (!mark->symbolPixmap().isNull()) { #ifdef BATCH_RENDERING QRect symbolRect = mark->symbolPixmap().rect(); QPainter::PixmapFragment pixmapFragment = QPainter::PixmapFragment::create(QPointF(symbolPos+symbolRect.center()),QRectF(symbolRect)); auto iter = hash.find(mark->symbolId()); if (iter == hash.end()) { Fragment fragment; fragment.pixmap = mark->symbolPixmap(); fragment.fragments << pixmapFragment; hash.insert(mark->symbolId(), fragment); } else { auto & fragment = iter.value(); fragment.fragments << pixmapFragment; } #else painter->drawPixmap( symbolPos, mark->symbolPixmap() ); #endif } if (!mark->labelPixmap().isNull()) { painter->drawPixmap( labelRect, mark->labelPixmap() ); } } } else { // simple case, one draw per placemark if (!mark->symbolPixmap().isNull()) { #ifdef BATCH_RENDERING QRect symbolRect = mark->symbolPixmap().rect(); QPainter::PixmapFragment pixmapFragment = QPainter::PixmapFragment::create(QPointF(symbolPos+symbolRect.center()),QRectF(symbolRect)); auto iter = hash.find(mark->symbolId()); if (iter == hash.end()) { Fragment fragment; fragment.pixmap = mark->symbolPixmap(); fragment.fragments << pixmapFragment; hash.insert(mark->symbolId(), fragment); } else { auto & fragment = iter.value(); fragment.fragments << pixmapFragment; } #else painter->drawPixmap( symbolPos, mark->symbolPixmap() ); #endif } if (!mark->labelPixmap().isNull()) { painter->drawPixmap( labelRect, mark->labelPixmap() ); } } } #ifdef BATCH_RENDERING for (auto iter = hash.begin(), end = hash.end(); iter != end; ++iter) { auto const & fragment = iter.value(); if (m_debugModeEnabled) { QPixmap debugPixmap(fragment.pixmap.size()); QColor backgroundColor; QString idStr = iter.key().section('/', -1); if (idStr.length() > 2) { idStr.remove("shop_"); backgroundColor = QColor( (10 * (int)(idStr[0].toLatin1()))%255, (10 * (int)(idStr[1].toLatin1()))%255, (10 * (int)(idStr[2].toLatin1()))%255 ); } else { backgroundColor = QColor((quint64)(&iter.key())); } debugPixmap.fill(backgroundColor); QPainter pixpainter; pixpainter.begin(&debugPixmap); pixpainter.drawPixmap(0, 0, fragment.pixmap); pixpainter.end(); iter.value().pixmap = debugPixmap; } painter->drawPixmapFragments(fragment.fragments.data(), fragment.fragments.size(), fragment.pixmap); } #endif if (m_debugModeEnabled) { renderDebug(geoPainter, viewport, visiblePlacemarks); } return true; } RenderState PlacemarkLayer::renderState() const { return RenderState(QStringLiteral("Placemarks")); } QString PlacemarkLayer::runtimeTrace() const { return m_layout.runtimeTrace(); } QVector PlacemarkLayer::whichPlacemarkAt( const QPoint &pos ) { return m_layout.whichPlacemarkAt( pos ); } bool PlacemarkLayer::hasPlacemarkAt(const QPoint &pos) { return m_layout.hasPlacemarkAt(pos); } bool PlacemarkLayer::isDebugModeEnabled() const { return m_debugModeEnabled; } void PlacemarkLayer::setDebugModeEnabled(bool enabled) { m_debugModeEnabled = enabled; } void PlacemarkLayer::setShowPlaces( bool show ) { m_layout.setShowPlaces( show ); } void PlacemarkLayer::setShowCities( bool show ) { m_layout.setShowCities( show ); } void PlacemarkLayer::setShowTerrain( bool show ) { m_layout.setShowTerrain( show ); } void PlacemarkLayer::setShowOtherPlaces( bool show ) { m_layout.setShowOtherPlaces( show ); } void PlacemarkLayer::setShowLandingSites( bool show ) { m_layout.setShowLandingSites( show ); } void PlacemarkLayer::setShowCraters( bool show ) { m_layout.setShowCraters( show ); } void PlacemarkLayer::setShowMaria( bool show ) { m_layout.setShowMaria( show ); } void PlacemarkLayer::requestStyleReset() { m_layout.requestStyleReset(); } void PlacemarkLayer::setTileLevel(int tileLevel) { m_tileLevel = tileLevel; } // Test if there a bug in the X server which makes // text fully transparent if it gets written on // QPixmaps that were initialized by filling them // with Qt::transparent bool PlacemarkLayer::testXBug() { QString testchar( "K" ); QFont font( "Sans Serif", 10 ); int fontheight = QFontMetrics( font ).height(); int fontwidth = QFontMetrics( font ).width(testchar); int fontascent = QFontMetrics( font ).ascent(); QPixmap pixmap( fontwidth, fontheight ); pixmap.fill( Qt::transparent ); QPainter textpainter; textpainter.begin( &pixmap ); textpainter.setPen( QColor( 0, 0, 0, 255 ) ); textpainter.setFont( font ); textpainter.drawText( 0, fontascent, testchar ); textpainter.end(); QImage image = pixmap.toImage(); for ( int x = 0; x < fontwidth; ++x ) { for ( int y = 0; y < fontheight; ++y ) { if ( qAlpha( image.pixel( x, y ) ) > 0 ) return false; } } return true; } void PlacemarkLayer::renderDebug(GeoPainter *painter, ViewportParams *viewport, const QVector &placemarks) const { painter->save(); painter->setFont(QFont(QStringLiteral("Sans Serif"), 7)); painter->setBrush(QBrush(Qt::NoBrush)); auto const latLonAltBox = viewport->viewLatLonAltBox(); - typedef QSet Placemarks; + using Placemarks = QSet; Placemarks const hidden = Placemarks::fromList(m_layout.visiblePlacemarks()).subtract(Placemarks::fromList(placemarks.toList())); for (auto placemark: hidden) { bool const inside = latLonAltBox.contains(placemark->coordinates()); painter->setPen(QPen(QColor(inside ? Qt::red : Qt::darkYellow))); painter->drawRect(placemark->boundingBox()); } painter->setPen(QPen(QColor(Qt::blue))); for (auto placemark: placemarks) { painter->drawRect(placemark->boundingBox()); } painter->setPen(QPen(QColor(Qt::green))); for (auto placemark: placemarks) { painter->drawRect(placemark->labelRect()); painter->drawRect(placemark->symbolRect()); } auto const height = painter->fontMetrics().height(); painter->setPen(QPen(QColor(Qt::black))); for (auto placemark: placemarks) { QPoint position = placemark->symbolRect().bottomLeft().toPoint() + QPoint(0, qRound(0.8 * height)); auto const popularity = placemark->placemark()->popularity(); painter->drawText(position, QStringLiteral("p: %1").arg(popularity)); position -= QPoint(0, placemark->symbolRect().height() + height); auto const zoomLevel = placemark->placemark()->zoomLevel(); painter->drawText(position, QStringLiteral("z: %1").arg(zoomLevel)); } painter->restore(); } void PlacemarkLayer::setLevelTagDebugModeEnabled(bool enabled) { if (m_levelTagDebugModeEnabled != enabled) { m_levelTagDebugModeEnabled = enabled; emit repaintNeeded(); } } bool PlacemarkLayer::levelTagDebugModeEnabled() const { return m_levelTagDebugModeEnabled; } void PlacemarkLayer::setDebugLevelTag(int level) { if (m_debugLevelTag != level) { m_debugLevelTag = level; emit repaintNeeded(); } } #include "moc_PlacemarkLayer.cpp" diff --git a/src/lib/marble/routing/RoutingLayer.cpp b/src/lib/marble/routing/RoutingLayer.cpp index 70f3510e7..9a22f792a 100644 --- a/src/lib/marble/routing/RoutingLayer.cpp +++ b/src/lib/marble/routing/RoutingLayer.cpp @@ -1,817 +1,817 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2010 Dennis Nienhüser // #include "RoutingLayer.h" #include "GeoDataCoordinates.h" #include "GeoDataLineString.h" #include "GeoPainter.h" #include "MarblePlacemarkModel.h" #include "MarbleWidget.h" #include "MarbleWidgetPopupMenu.h" #include "RoutingModel.h" #include "Route.h" #include "RouteRequest.h" #include "MarbleModel.h" #include "AlternativeRoutesModel.h" #include "RoutingManager.h" #include "Maneuver.h" #include "RenderState.h" #include #include #include #include #include #include #include namespace Marble { class RoutingLayerPrivate { template struct PaintRegion { T index; QRegion region; PaintRegion( const T &index_, const QRegion ®ion_ ) : index( index_ ), region( region_ ) { // nothing to do } }; - typedef PaintRegion ModelRegion; - typedef PaintRegion RequestRegion; + using ModelRegion = PaintRegion; + using RequestRegion = PaintRegion; public: RoutingLayer *const q; QList m_instructionRegions; QList m_regions; QList m_alternativeRouteRegions; QList m_placemarks; QRegion m_routeRegion; int m_movingIndex; MarbleWidget *const m_marbleWidget; QPixmap m_targetPixmap; QPixmap m_standardRoutePoint; QPixmap m_activeRoutePoint; QRect m_dirtyRect; QPoint m_dropStopOver; QPoint m_dragStopOver; int m_dragStopOverRightIndex; RoutingModel *const m_routingModel; MarblePlacemarkModel *m_placemarkModel; QItemSelectionModel *m_selectionModel; QSize m_pixmapSize; RouteRequest *const m_routeRequest; MarbleWidgetPopupMenu *m_contextMenu; QAction *m_removeViaPointAction; int m_activeMenuIndex; AlternativeRoutesModel *const m_alternativeRoutesModel; ViewContext m_viewContext; bool m_viewportChanged; bool m_isInteractive; /** Constructor */ explicit RoutingLayerPrivate( RoutingLayer *parent, MarbleWidget *widget ); /** Update the cached drag position. Use an empty point to clear it. */ void storeDragPosition( const QPoint &position ); // The following methods are mostly only called at one place in the code, but often // Inlined to avoid the function call overhead. Having functions here is just to // keep the code clean /** Returns the same color as the given one with its alpha channel adjusted to the given value */ static inline QColor alphaAdjusted( const QColor &color, int alpha ); static QPixmap createRoutePoint(const QColor &penColor, const QColor &brushColor); /** * Returns the start or destination position if Ctrl key is among the * provided modifiers, the cached insert position otherwise */ inline int viaInsertPosition( Qt::KeyboardModifiers modifiers ) const; /** Paint icons for each placemark in the placemark model */ inline void renderPlacemarks( GeoPainter *painter ); /** Paint waypoint polygon */ inline void renderRoute( GeoPainter *painter ); /** Paint turn instruction for selected items */ inline void renderAnnotations( GeoPainter *painter ) const; /** Paint alternative routes in gray */ inline void renderAlternativeRoutes( GeoPainter *painter ); /** Paint icons for trip points etc */ inline void renderRequest( GeoPainter *painter ); /** Insert via points or emit position signal, if appropriate */ inline bool handleMouseButtonRelease( QMouseEvent *e ); /** Select route instructions points, start dragging trip points */ inline bool handleMouseButtonPress( QMouseEvent *e ); /** Dragging trip points, route polygon hovering */ inline bool handleMouseMove( QMouseEvent *e ); /** True if the given point (screen coordinates) is among the route instruction points */ inline bool isInfoPoint( const QPoint &point ); /** True if the given point (screen coordinates) is above an alternative route */ inline bool isAlternativeRoutePoint( const QPoint &point ); /** Paint the stopover indicator pixmap at the given position. Also repaints the old position */ inline void paintStopOver( QRect position ); /** Removes the stopover indicator pixmap. Also repaints its old position */ inline void clearStopOver(); }; RoutingLayerPrivate::RoutingLayerPrivate( RoutingLayer *parent, MarbleWidget *widget ) : q( parent ), m_movingIndex( -1 ), m_marbleWidget( widget ), m_targetPixmap(QStringLiteral(":/data/bitmaps/routing_pick.png")), m_standardRoutePoint(createRoutePoint(widget->model()->routingManager()->routeColorStandard(), widget->model()->routingManager()->routeColorAlternative())), m_activeRoutePoint(createRoutePoint(widget->model()->routingManager()->routeColorHighlighted(), alphaAdjusted(Oxygen::hotOrange4, 200))), m_dragStopOverRightIndex(-1), m_routingModel( widget->model()->routingManager()->routingModel() ), m_placemarkModel( nullptr ), m_selectionModel( nullptr ), m_pixmapSize( 22, 22 ), m_routeRequest( widget->model()->routingManager()->routeRequest() ), m_activeMenuIndex( -1 ), m_alternativeRoutesModel( widget->model()->routingManager()->alternativeRoutesModel() ), m_viewContext( Still ), m_viewportChanged( true ), m_isInteractive( true ) { m_contextMenu = new MarbleWidgetPopupMenu( m_marbleWidget, m_marbleWidget->model() ); m_removeViaPointAction = new QAction( QObject::tr( "&Remove this destination" ), q ); QObject::connect( m_removeViaPointAction, SIGNAL(triggered()), q, SLOT(removeViaPoint()) ); m_contextMenu->addAction( Qt::RightButton, m_removeViaPointAction ); QAction *exportAction = new QAction( QObject::tr( "&Export route..." ), q ); QObject::connect( exportAction, SIGNAL(triggered()), q, SLOT(exportRoute()) ); m_contextMenu->addAction( Qt::RightButton, exportAction ); if ( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ) { m_pixmapSize = QSize( 38, 38 ); } } int RoutingLayerPrivate::viaInsertPosition( Qt::KeyboardModifiers modifiers ) const { if ( modifiers & Qt::ControlModifier ) { bool leftHand = m_routeRequest->size() / 2 >= m_dragStopOverRightIndex; if ( leftHand && m_routeRequest->size() > 2 ) { return 0; } else { return m_routeRequest->size(); } } else { return m_dragStopOverRightIndex; } } void RoutingLayerPrivate::renderPlacemarks( GeoPainter *painter ) { m_placemarks.clear(); painter->setPen( QColor( Qt::black ) ); for ( int i = 0; i < m_placemarkModel->rowCount(); ++i ) { QModelIndex index = m_placemarkModel->index( i, 0 ); QVariant data = index.data( MarblePlacemarkModel::CoordinateRole ); if ( index.isValid() && !data.isNull() ) { GeoDataCoordinates pos = data.value(); QPixmap pixmap = index.data( Qt::DecorationRole ).value(); if ( !pixmap.isNull() && m_selectionModel->isSelected( index ) ) { QIcon selected = QIcon( pixmap ); QPixmap result = selected.pixmap( m_pixmapSize, QIcon::Selected, QIcon::On ); painter->drawPixmap( pos, result ); } else { painter->drawPixmap( pos, pixmap ); } const QRegion region = painter->regionFromPixmapRect(pos, m_targetPixmap.width(), m_targetPixmap.height()); m_placemarks.push_back( ModelRegion( index, region ) ); } } } void RoutingLayerPrivate::renderAlternativeRoutes( GeoPainter *painter ) { QPen alternativeRoutePen( m_marbleWidget->model()->routingManager()->routeColorAlternative() ); alternativeRoutePen.setWidth( 5 ); painter->setPen( alternativeRoutePen ); for ( int i=0; irowCount(); ++i ) { const GeoDataDocument *route = m_alternativeRoutesModel->route(i); if ( route && route != m_alternativeRoutesModel->currentRoute() ) { const GeoDataLineString* points = AlternativeRoutesModel::waypoints( route ); if ( points ) { painter->drawPolyline( *points ); if ( m_viewportChanged && m_isInteractive && m_viewContext == Still ) { QRegion region = painter->regionFromPolyline( *points, 8 ); m_alternativeRouteRegions.push_back( RequestRegion( i, region ) ); } } } } } void RoutingLayerPrivate::renderRoute( GeoPainter *painter ) { GeoDataLineString waypoints = m_routingModel->route().path(); QPen standardRoutePen( m_marbleWidget->model()->routingManager()->routeColorStandard() ); standardRoutePen.setWidth( 5 ); if ( m_marbleWidget->model()->routingManager()->state() == RoutingManager::Downloading ) { standardRoutePen.setStyle( Qt::DotLine ); } painter->setPen( standardRoutePen ); painter->drawPolyline( waypoints ); if ( m_viewportChanged && m_viewContext == Still ) { int const offset = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ? 24 : 8; if ( m_isInteractive ) { m_routeRegion = painter->regionFromPolyline( waypoints, offset ); } } standardRoutePen.setWidth( 2 ); painter->setPen( standardRoutePen ); // Map matched position //painter->setBrush( QBrush( Oxygen::brickRed4) ); //painter->drawEllipse( m_routingModel->route().positionOnRoute(), 8, 8 ); painter->setBrush( QBrush( m_marbleWidget->model()->routingManager()->routeColorAlternative() ) ); if ( !m_dropStopOver.isNull() ) { int dx = 1 + m_pixmapSize.width() / 2; int dy = 1 + m_pixmapSize.height() / 2; QPoint center = m_dropStopOver - QPoint( dx, dy ); painter->drawPixmap( center, m_targetPixmap ); if ( !m_dragStopOver.isNull() && m_dragStopOverRightIndex >= 0 && m_dragStopOverRightIndex <= m_routeRequest->size() ) { QPoint moved = m_dropStopOver - m_dragStopOver; if ( moved.manhattanLength() > 10 ) { qreal lon( 0.0 ), lat( 0.0 ); if ( m_marbleWidget->geoCoordinates( m_dropStopOver.x(), m_dropStopOver.y(), lon, lat, GeoDataCoordinates::Radian ) ) { GeoDataCoordinates drag( lon, lat ); standardRoutePen.setStyle( Qt::DotLine ); painter->setPen( standardRoutePen ); GeoDataLineString lineString; if ( m_dragStopOverRightIndex > 0 ) { lineString << m_routeRequest->at( m_dragStopOverRightIndex-1 ); } lineString << drag; if ( m_dragStopOverRightIndex < m_routeRequest->size() ) { lineString << m_routeRequest->at( m_dragStopOverRightIndex ); } painter->drawPolyline( lineString ); standardRoutePen.setStyle( Qt::SolidLine ); painter->setPen( standardRoutePen ); } } } } if ( m_viewContext == Animation ) { return; } if( m_routingModel->rowCount() == m_routingModel->route().size() ) { m_instructionRegions.clear(); QPen activeRouteSegmentPen(m_marbleWidget->model()->routingManager()->routeColorHighlighted()); activeRouteSegmentPen.setWidth(6); if (m_marbleWidget->model()->routingManager()->state() == RoutingManager::Downloading) { activeRouteSegmentPen.setStyle(Qt::DotLine); } painter->setPen(activeRouteSegmentPen); for ( int i = 0; i < m_routingModel->rowCount(); ++i ) { QModelIndex index = m_routingModel->index( i, 0 ); GeoDataCoordinates pos = index.data( MarblePlacemarkModel::CoordinateRole ).value(); if ( m_selectionModel && m_selectionModel->selection().contains( index ) ) { const RouteSegment &segment = m_routingModel->route().at( i ); const GeoDataLineString currentRoutePoints = segment.path(); painter->drawPolyline( currentRoutePoints ); painter->drawPixmap(pos, m_activeRoutePoint); } else { painter->drawPixmap(pos, m_standardRoutePoint); } if ( m_isInteractive ) { QRegion region = painter->regionFromEllipse( pos, 12, 12 ); m_instructionRegions.push_front( ModelRegion( index, region ) ); } } } if( !m_routingModel->deviatedFromRoute() ) { GeoDataCoordinates location = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().position(); QString nextInstruction = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().instructionText(); if( !nextInstruction.isEmpty() ) { painter->drawPixmap(location, m_activeRoutePoint); } } } void RoutingLayerPrivate::renderAnnotations( GeoPainter *painter ) const { if ( !m_selectionModel || m_selectionModel->selection().isEmpty() ) { // nothing to do return; } for ( int i = 0; i < m_routingModel->rowCount(); ++i ) { QModelIndex index = m_routingModel->index( i, 0 ); if ( m_selectionModel->selection().contains( index ) ) { bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; GeoDataCoordinates pos = index.data( MarblePlacemarkModel::CoordinateRole ).value(); painter->setPen( QColor( Qt::black ) ); painter->setBrush( QBrush( Oxygen::sunYellow6 ) ); painter->drawAnnotation( pos, index.data().toString(), QSize( smallScreen ? 240 : 120, 0 ), 10, 30, 5, 5 ); } } } void RoutingLayerPrivate::renderRequest( GeoPainter *painter ) { m_regions.clear(); for ( int i = 0; i < m_routeRequest->size(); ++i ) { const GeoDataCoordinates pos = m_routeRequest->at( i ); if ( pos.isValid() ) { QPixmap pixmap = m_routeRequest->pixmap( i ); painter->drawPixmap( pos, pixmap ); const QRegion region = painter->regionFromPixmapRect(pos, pixmap.width(), pixmap.height()); m_regions.push_front( RequestRegion( i, region ) ); } } } void RoutingLayerPrivate::storeDragPosition( const QPoint &pos ) { m_dragStopOver = pos; m_dragStopOverRightIndex = -1; qreal lon( 0.0 ), lat( 0.0 ); if ( m_routeRequest && !pos.isNull() && m_marbleWidget->geoCoordinates( pos.x(), pos.y(), lon, lat, GeoDataCoordinates::Radian ) ) { GeoDataCoordinates waypoint( lon, lat ); m_dragStopOverRightIndex = m_routingModel->rightNeighbor( waypoint, m_routeRequest ); } } QColor RoutingLayerPrivate::alphaAdjusted( const QColor &color, int alpha ) { QColor result( color ); result.setAlpha( alpha ); return result; } QPixmap RoutingLayerPrivate::createRoutePoint(const QColor &penColor, const QColor &brushColor) { QPen pen(penColor); pen.setWidth(2); const QBrush brush(brushColor); QPixmap routePoint(QSize(8, 8)); routePoint.fill(Qt::transparent); QPainter painter(&routePoint); painter.setRenderHint(QPainter::Antialiasing, true); painter.setPen(pen); painter.setBrush(brush); painter.drawEllipse(1, 1, 6, 6); return routePoint; } bool RoutingLayerPrivate::handleMouseButtonPress( QMouseEvent *e ) { for( const RequestRegion ®ion: m_regions ) { if ( region.region.contains( e->pos() ) ) { if ( e->button() == Qt::LeftButton ) { m_movingIndex = region.index; m_dropStopOver = QPoint(); m_dragStopOver = QPoint(); return true; } else if ( e->button() == Qt::RightButton ) { m_removeViaPointAction->setEnabled( true ); m_activeMenuIndex = region.index; m_contextMenu->showRmbMenu( e->x(), e->y() ); return true; } else return false; } } for( const ModelRegion ®ion: m_instructionRegions ) { if ( region.region.contains( e->pos() ) && m_selectionModel ) { if ( e->button() == Qt::LeftButton ) { QItemSelectionModel::SelectionFlag command = QItemSelectionModel::ClearAndSelect; if ( m_selectionModel->isSelected( region.index ) ) { command = QItemSelectionModel::Clear; } m_selectionModel->select( region.index, command ); m_dropStopOver = e->pos(); storeDragPosition( e->pos() ); // annotation and old annotation are dirty, large region emit q->repaintNeeded(); return true; } else if ( e->button() == Qt::RightButton ) { m_removeViaPointAction->setEnabled( false ); m_contextMenu->showRmbMenu( e->x(), e->y() ); return true; } else return false; } } if ( m_routeRegion.contains( e->pos() ) ) { if ( e->button() == Qt::LeftButton ) { /** @todo: Determine the neighbored via points and insert in order */ m_dropStopOver = e->pos(); storeDragPosition( e->pos() ); return true; } else if ( e->button() == Qt::RightButton ) { m_removeViaPointAction->setEnabled( false ); m_contextMenu->showRmbMenu( e->x(), e->y() ); return true; } else return false; } if ( e->button() != Qt::LeftButton ) { return false; } for( const RequestRegion ®ion: m_alternativeRouteRegions ) { if ( region.region.contains( e->pos() ) ) { m_alternativeRoutesModel->setCurrentRoute( region.index ); return true; } } for( const ModelRegion ®ion: m_placemarks ) { if ( region.region.contains( e->pos() ) ) { emit q->placemarkSelected( region.index ); return true; } } return false; } bool RoutingLayerPrivate::handleMouseButtonRelease( QMouseEvent *e ) { if ( e->button() != Qt::LeftButton ) { return false; } if ( m_movingIndex >= 0 ) { m_movingIndex = -1; clearStopOver(); m_marbleWidget->model()->routingManager()->retrieveRoute(); return true; } if ( !m_dropStopOver.isNull() && !m_dragStopOver.isNull() ) { QPoint moved = e->pos() - m_dragStopOver; if ( moved.manhattanLength() < 10 ) { return false; } qreal lon( 0.0 ), lat( 0.0 ); if ( m_dragStopOverRightIndex >= 0 && m_dragStopOverRightIndex <= m_routeRequest->size() && m_marbleWidget->geoCoordinates( m_dropStopOver.x(), m_dropStopOver.y(), lon, lat, GeoDataCoordinates::Radian ) ) { GeoDataCoordinates position( lon, lat ); m_dragStopOverRightIndex = viaInsertPosition( e->modifiers() ); m_routeRequest->insert( m_dragStopOverRightIndex, position ); clearStopOver(); m_marbleWidget->model()->routingManager()->retrieveRoute(); return true; } } return false; } bool RoutingLayerPrivate::handleMouseMove( QMouseEvent *e ) { qreal lon( 0.0 ), lat( 0.0 ); if ( m_marbleWidget->geoCoordinates( e->pos().x(), e->pos().y(), lon, lat, GeoDataCoordinates::Radian ) ) { if ( m_movingIndex >= 0 ) { GeoDataCoordinates moved( lon, lat ); m_routeRequest->setPosition( m_movingIndex, moved ); m_marbleWidget->setCursor( Qt::ArrowCursor ); } else if ( !m_dragStopOver.isNull() ) { // Repaint only that region of the map that is affected by the change m_dragStopOverRightIndex = viaInsertPosition( e->modifiers() ); QRect dirty = m_routeRegion.boundingRect(); dirty |= QRect( m_dropStopOver, m_pixmapSize ); dirty |= QRect( e->pos(), m_pixmapSize ); if ( e->buttons() & Qt::LeftButton ) { m_dropStopOver = e->pos(); } else { m_dragStopOver = QPoint(); m_dropStopOver = QPoint(); } emit q->repaintNeeded( dirty ); m_marbleWidget->setCursor( Qt::ArrowCursor ); } else if ( isInfoPoint( e->pos() ) ) { clearStopOver(); m_marbleWidget->setCursor( Qt::ArrowCursor ); } else if ( m_routeRegion.contains( e->pos() ) ) { m_dropStopOver = e->pos(); m_marbleWidget->setCursor( Qt::ArrowCursor ); } else if ( !m_dropStopOver.isNull() ) { clearStopOver(); } else if ( isAlternativeRoutePoint( e->pos() ) ) { m_marbleWidget->setCursor( Qt::ArrowCursor ); } else { return false; } // Update pixmap in the map (old and new position needs repaint) paintStopOver( QRect( e->pos(), m_pixmapSize ) ); return true; } return false; } bool RoutingLayerPrivate::isInfoPoint( const QPoint &point ) { for( const RequestRegion ®ion: m_regions ) { if ( region.region.contains( point ) ) { return true; } } for( const ModelRegion ®ion: m_instructionRegions ) { if ( region.region.contains( point ) ) { return true; } } return false; } bool RoutingLayerPrivate::isAlternativeRoutePoint( const QPoint &point ) { for( const RequestRegion ®ion: m_alternativeRouteRegions ) { if ( region.region.contains( point ) ) { return true; } } return false; } void RoutingLayerPrivate::paintStopOver( QRect dirty ) { emit q->repaintNeeded( m_dirtyRect ); int dx = 1 + m_pixmapSize.width() / 2; int dy = 1 + m_pixmapSize.height() / 2; dirty.adjust( -dx, -dy, -dx, -dy ); emit q->repaintNeeded( dirty ); m_dirtyRect = dirty; } void RoutingLayerPrivate::clearStopOver() { m_dropStopOver = QPoint(); m_dragStopOver = QPoint(); emit q->repaintNeeded( m_dirtyRect ); } RoutingLayer::RoutingLayer( MarbleWidget *widget, QWidget *parent ) : QObject( parent ), d( new RoutingLayerPrivate( this, widget ) ) { connect( widget->model()->routingManager(), SIGNAL(stateChanged(RoutingManager::State)), this, SLOT(updateRouteState()) ); connect( widget, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)), this, SLOT(setViewportChanged()) ); connect(widget->model()->routingManager()->alternativeRoutesModel(), SIGNAL(currentRouteChanged(const GeoDataDocument*)), this, SLOT(setViewportChanged()) ); connect(widget->model()->routingManager()->alternativeRoutesModel(), SIGNAL(currentRouteChanged(const GeoDataDocument*)), this, SIGNAL(repaintNeeded()) ); connect( widget->model()->routingManager()->alternativeRoutesModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(showAlternativeRoutes()) ); } RoutingLayer::~RoutingLayer() { delete d; } QStringList RoutingLayer::renderPosition() const { return QStringList(QStringLiteral("HOVERS_ABOVE_SURFACE")); } qreal RoutingLayer::zValue() const { return 1.0; } bool RoutingLayer::render( GeoPainter *painter, ViewportParams *viewport, const QString& renderPos, GeoSceneLayer *layer ) { Q_UNUSED( viewport ) Q_UNUSED( renderPos ) Q_UNUSED( layer ) painter->save(); if ( d->m_placemarkModel) { d->renderPlacemarks( painter ); } if ( d->m_alternativeRoutesModel ) { d->renderAlternativeRoutes( painter ); } d->renderRoute( painter ); if ( d->m_routeRequest) { d->renderRequest( painter ); } d->renderAnnotations( painter ); painter->restore(); if ( d->m_viewportChanged && d->m_viewContext == Still ) { d->m_viewportChanged = false; } return true; } RenderState RoutingLayer::renderState() const { return RenderState(QStringLiteral("Routing"), d->m_marbleWidget->model()->routingManager()->state() == RoutingManager::Downloading ? WaitingForUpdate : Complete); } bool RoutingLayer::eventFilter( QObject *obj, QEvent *event ) { Q_UNUSED( obj ) if ( !d->m_isInteractive ) { return false; } if ( event->type() == QEvent::MouseButtonPress ) { QMouseEvent *e = static_cast( event ); return d->handleMouseButtonPress( e ); } if ( event->type() == QEvent::MouseButtonRelease ) { QMouseEvent *e = static_cast( event ); return d->handleMouseButtonRelease( e ); } if ( event->type() == QEvent::MouseMove ) { QMouseEvent *e = static_cast( event ); return d->handleMouseMove( e ); } return false; } void RoutingLayer::setPlacemarkModel ( MarblePlacemarkModel *model ) { d->m_placemarkModel = model; setViewportChanged(); } void RoutingLayer::synchronizeWith( QItemSelectionModel *selection ) { d->m_selectionModel = selection; } void RoutingLayer::removeViaPoint() { if ( d->m_activeMenuIndex >= 0 ) { d->m_routeRequest->remove( d->m_activeMenuIndex ); d->m_activeMenuIndex = -1; emit repaintNeeded(); d->m_marbleWidget->model()->routingManager()->retrieveRoute(); } } void RoutingLayer::showAlternativeRoutes() { setViewportChanged(); emit repaintNeeded(); } void RoutingLayer::exportRoute() { QString fileName = QFileDialog::getSaveFileName( d->m_marbleWidget, tr( "Export Route" ), // krazy:exclude=qclasses QDir::homePath(), tr( "GPX and KML files (*.gpx *.kml)" ) ); if ( !fileName.isEmpty() ) { if ( fileName.endsWith( QLatin1String( ".gpx" ), Qt::CaseInsensitive ) ) { QFile gpx( fileName ); if ( gpx.open( QFile::WriteOnly) ) { d->m_routingModel->exportGpx( &gpx ); gpx.close(); } } else { d->m_marbleWidget->model()->routingManager()->saveRoute( fileName ); } } } void RoutingLayer::updateRouteState() { setViewportChanged(); emit repaintNeeded(); } void RoutingLayer::setViewportChanged() { d->m_viewportChanged = true; d->m_routeRegion = QRegion(); d->m_instructionRegions.clear(); d->m_alternativeRouteRegions.clear(); } void RoutingLayer::setViewContext( ViewContext viewContext ) { d->m_viewContext = viewContext; } void RoutingLayer::setInteractive( bool interactive ) { d->m_isInteractive = interactive; } bool RoutingLayer::isInteractive() const { return d->m_isInteractive; } QString RoutingLayer::runtimeTrace() const { return QStringLiteral("Routing Layer"); } } // namespace Marble #include "moc_RoutingLayer.cpp" diff --git a/src/lib/marble/routing/instructions/RoutingInstruction.h b/src/lib/marble/routing/instructions/RoutingInstruction.h index a99d3f9ed..610a143a8 100644 --- a/src/lib/marble/routing/instructions/RoutingInstruction.h +++ b/src/lib/marble/routing/instructions/RoutingInstruction.h @@ -1,164 +1,164 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2010 Dennis Nienhüser // #ifndef MARBLE_ROUTINGINSTRUCTION_H #define MARBLE_ROUTINGINSTRUCTION_H #include "RoutingWaypoint.h" #include "RoutingPoint.h" #include "marble_export.h" #include #include class QTextStream; namespace Marble { /** * Stores data related to one instruction: Road name, angle to predecessor, * associated waypoints etc. Can be streamed directly to a QTextStream. */ class MARBLE_EXPORT RoutingInstruction { public: enum TurnType { Unknown = 0, Continue = 13 /** Continue on the next street */, Merge = 14, Straight = 1, SlightRight = 2, Right = 3, SharpRight = 4, TurnAround = 5 /** Perform a u-turn */, SharpLeft = 6, Left = 7, SlightLeft = 8, RoundaboutFirstExit = 9 /** Enter the roundabout and leave at the first exit */, RoundaboutSecondExit = 10 /** Enter the roundabout and leave at the second exit */, RoundaboutThirdExit = 11 /** Enter the roundabout and leave at the third exit */, RoundaboutExit = 12 /** At the point where the roundabout should be exited */, ExitLeft = 15, ExitRight = 16 }; /** Constructor */ explicit RoutingInstruction( const RoutingWaypoint &item = RoutingWaypoint() ); /** * Append data of the given item, returns true if item's street * name matches instructions street name */ bool append( const RoutingWaypoint &item, int angle ); /** Name of the road to turn into */ QString roadName() const; /** OSM type of the road to turn into */ QString roadType() const; /** Estimated number of seconds to the route destination */ int secondsLeft() const; /** Waypoints from the last instruction to this instruction */ QVector points() const; /** * Contains the intersection point and points near it on the previous and current road. * Near is taken as that waypoint with the largest different to the intersection point * that does not exceed 50 meter. */ QVector intersectionPoints() const; /** The angle between the two turn roads, in radians */ qreal angleToPredecssor() const; /** Previous turn road. Will be 0 for the first one (route start) */ RoutingInstruction* predecessor(); /** Const overload for #predecessor */ const RoutingInstruction* predecessor() const; /** Change the predecessor */ void setPredecessor( RoutingInstruction* predecessor ); /** Next turn road. Will be 0 for the last one (destination) */ RoutingInstruction* successor(); /** Const overload for #successor */ const RoutingInstruction* successor() const; /** Change the successor */ void setSuccessor( RoutingInstruction* successor ); /** The accumulated distance of all waypoints belonging to this instruction */ qreal distance() const; /** The distance from the route start */ qreal distanceFromStart() const; /** The distance to the route end. Includes the own distance */ qreal distanceToEnd() const; TurnType turnType() const; /** Formats the instruction (road name) for a human reader */ QString nextRoadInstruction() const; /** Formats the instruction (distance to next instruction) for a human reader */ QString nextDistanceInstruction() const; /** Formats the instruction (duration to destination) for a human reader */ QString totalDurationRemaining() const; /** Formats the instruction for a human reader */ QString instructionText() const; static QString generateRoadInstruction( TurnType turnType, const QString &roadName ); protected: int roundaboutExitNumber() const; private: void calculateAngle(); void calculateTurnType(); QVector m_points; QVector m_intersectionPoints; QString m_roadName; QString m_roadType; int m_secondsLeft; qreal m_angleToPredecessor; TurnType m_turnType; int m_roundaboutExit; RoutingInstruction* m_predecessor; RoutingInstruction* m_successor; }; QTextStream& operator<<( QTextStream& stream, const RoutingInstruction &i ); -typedef QVector RoutingInstructions; +using RoutingInstructions = QVector; } // namespace Marble Q_DECLARE_METATYPE( Marble::RoutingInstruction::TurnType ) #endif // MARBLE_ROUTINGINSTRUCTION_H diff --git a/src/lib/marble/routing/instructions/RoutingWaypoint.h b/src/lib/marble/routing/instructions/RoutingWaypoint.h index 708b3d27d..dacc860a7 100644 --- a/src/lib/marble/routing/instructions/RoutingWaypoint.h +++ b/src/lib/marble/routing/instructions/RoutingWaypoint.h @@ -1,80 +1,80 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2010 Dennis Nienhüser // #ifndef MARBLE_ROUTINGWAYPOINT_H #define MARBLE_ROUTINGWAYPOINT_H #include "RoutingPoint.h" #include "marble_export.h" #include #include namespace Marble { /** * Stores one line of gosmore/routino output */ class MARBLE_EXPORT RoutingWaypoint { public: /** Junction types that affect instructions */ enum JunctionType { Roundabout, Other, None }; /** Constructor */ RoutingWaypoint(); /** Convenience constructor to initialize members */ RoutingWaypoint( const RoutingPoint &point, JunctionType junctionType, const QString &junctionTypeRaw, const QString &roadType, int secondsRemaining, const QString &roadName ); /** Associated geo point */ RoutingPoint point() const; /** Parsed junction type */ JunctionType junctionType() const; /** Junction type originally passed */ QString junctionTypeRaw() const; /** OSM type of the road */ QString roadType() const; /** Estimated seconds remaining until the route destination is reached */ int secondsRemaining() const; /** OSM name of the road */ QString roadName() const; private: RoutingPoint m_point; JunctionType m_junctionType; QString m_junctionTypeRaw; QString m_roadType; int m_secondsRemaining; QString m_roadName; }; -typedef QVector RoutingWaypoints; +using RoutingWaypoints = QVector; } // namespace Marble #endif diff --git a/src/plugins/positionprovider/flightgear/FlightGearPositionProviderPlugin.cpp b/src/plugins/positionprovider/flightgear/FlightGearPositionProviderPlugin.cpp index 5acc19724..de914c44f 100644 --- a/src/plugins/positionprovider/flightgear/FlightGearPositionProviderPlugin.cpp +++ b/src/plugins/positionprovider/flightgear/FlightGearPositionProviderPlugin.cpp @@ -1,231 +1,231 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2012 Ralf Habacker // #include "FlightGearPositionProviderPlugin.h" #include "MarbleDebug.h" #include #include #include using namespace Marble; /* TRANSLATOR Marble::FlightGearPositionProviderPlugin */ using namespace std; FlightGearPositionProviderPlugin::FlightGearPositionProviderPlugin() : m_socket(nullptr), m_speed( 0.0 ), m_track( 0.0 ) { } FlightGearPositionProviderPlugin::~FlightGearPositionProviderPlugin() { delete m_socket; } QString FlightGearPositionProviderPlugin::name() const { return tr( "FlightGear position provider Plugin" ); } QString FlightGearPositionProviderPlugin::nameId() const { return QStringLiteral("flightgear"); } QString FlightGearPositionProviderPlugin::guiString() const { return tr( "FlightGear" ); } QString FlightGearPositionProviderPlugin::version() const { return QStringLiteral("1.0"); } QString FlightGearPositionProviderPlugin::description() const { return tr( "Reports the position of running flightgear application." ); } QString FlightGearPositionProviderPlugin::copyrightYears() const { return QStringLiteral("2012"); } QVector FlightGearPositionProviderPlugin::pluginAuthors() const { return QVector() << PluginAuthor(QStringLiteral("Ralf Habacker"), QStringLiteral("ralf.habacker@freenet.de")); } QIcon FlightGearPositionProviderPlugin::icon() const { return QIcon(); } void FlightGearPositionProviderPlugin::initialize() { m_status = PositionProviderStatusAcquiring; emit statusChanged( m_status ); m_socket = new QUdpSocket(this); m_socket->bind(QHostAddress::LocalHost, 5500); connect(m_socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); } /** fixed case where wrong date format is used '2404112' instead of '240412' */ bool fixBadGPRMC(QByteArray &line) { if (!line.startsWith("$GPRMC")) return false; QStringList parts = QString(line).split(QLatin1Char(',')); if (parts[9].size() == 7) { parts[9].remove(4,1); line = parts.join(QLatin1Char(',')).toLatin1(); // update crc int crc = 0; for(int i=1; i < line.size()-3; i++) { crc ^= (int) line[i]; } parts[11] = parts[11][0] + parts[11][1] + QString::number(crc, 16).toUpper(); line = parts.join(QLatin1Char(',')).toLatin1(); return true; } return false; } void FlightGearPositionProviderPlugin::readPendingDatagrams() { while (m_socket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(m_socket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; m_socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); - typedef QList::Iterator Iterator; + using Iterator = QList::Iterator; QList split = datagram.split('\n'); for (Iterator i = split.begin(); i != split.end(); i++) { fixBadGPRMC(*i); i->append( "\n" ); parseNmeaSentence( *i ); } } } void FlightGearPositionProviderPlugin::parseNmeaSentence( const QString &sentence ) { PositionProviderStatus oldStatus = m_status; GeoDataCoordinates oldPosition = m_position; if ( sentence.startsWith( QLatin1String( "$GPRMC" ) ) ) { QStringList const values = sentence.split(QLatin1Char(',')); if ( values.size() > 9 ) { if (values[2] == QLatin1String("A")) { m_speed = values[7].toDouble() * 0.514444; // knots => m/s m_track = values[8].toDouble(); QString const date = values[9] + QLatin1Char(' ') + values[1]; m_timestamp = QDateTime::fromString( date, "ddMMyy HHmmss" ); if (m_timestamp.date().year() <= 1930 && m_timestamp.date().year() >= 1900 ) { m_timestamp = m_timestamp.addYears( 100 ); // Qt range is 1900-1999 for two-digits } } // Flightgear submits geoposition twice in one datagram, once // in GPRMC and once in GPGGA. Parsing one is sufficient } } else if ( sentence.startsWith( QLatin1String( "$GPGGA" ) ) ) { QStringList const values = sentence.split(QLatin1Char(',')); if ( values.size() > 10 ) { if ( values[6] == nullptr ) { m_status = PositionProviderStatusAcquiring; // no fix } else { double const lat = parsePosition(values[2], values[3] == QLatin1String("S")); double const lon = parsePosition(values[4], values[5] == QLatin1String("W")); double const unitFactor = values[10] == QLatin1String("F") ? FT2M : 1.0; double const alt = unitFactor * values[9].toDouble(); m_position.set( lon, lat, alt, GeoDataCoordinates::Degree ); m_accuracy.level = GeoDataAccuracy::Detailed; m_status = PositionProviderStatusAvailable; } } } else { return; } if ( m_status != oldStatus ) { emit statusChanged( m_status ); } if ( m_position != oldPosition && m_status == PositionProviderStatusAvailable ) { emit positionChanged( m_position, m_accuracy ); } } double FlightGearPositionProviderPlugin::parsePosition( const QString &value, bool isNegative ) { double pos = value.toDouble(); pos = int( pos / 100.0 ) + ( pos - 100.0 * int( pos / 100.0 ) ) / 60.0; return isNegative ? -qAbs( pos ) : pos; } bool FlightGearPositionProviderPlugin::isInitialized() const { return m_socket; } PositionProviderPlugin* FlightGearPositionProviderPlugin::newInstance() const { return new FlightGearPositionProviderPlugin; } PositionProviderStatus FlightGearPositionProviderPlugin::status() const { return m_status; } GeoDataCoordinates FlightGearPositionProviderPlugin::position() const { return m_position; } GeoDataAccuracy FlightGearPositionProviderPlugin::accuracy() const { return m_accuracy; } qreal FlightGearPositionProviderPlugin::speed() const { return m_speed; } qreal FlightGearPositionProviderPlugin::direction() const { return m_track; } QDateTime FlightGearPositionProviderPlugin::timestamp() const { return m_timestamp; } QString FlightGearPositionProviderPlugin::error() const { return QString(); } #include "moc_FlightGearPositionProviderPlugin.cpp" diff --git a/src/plugins/render/elevationprofilefloatitem/ElevationProfilePlotAxis.h b/src/plugins/render/elevationprofilefloatitem/ElevationProfilePlotAxis.h index 07fd8b261..7a303ea18 100644 --- a/src/plugins/render/elevationprofilefloatitem/ElevationProfilePlotAxis.h +++ b/src/plugins/render/elevationprofilefloatitem/ElevationProfilePlotAxis.h @@ -1,76 +1,76 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2011-2012 Florian Eßer // #ifndef ELEVATIONPROFILEPLOTAXIS_H #define ELEVATIONPROFILEPLOTAXIS_H #include #include #include namespace Marble { struct AxisTick { int position; qreal value; AxisTick() : position(0), value(0.0) { } AxisTick(int position_, qreal value_) : position( position_ ), value( value_ ) { // nothing to do } }; -typedef QVector AxisTickList; +using AxisTickList = QVector; /** * @short A helper class handling a plot axis for the Elevation Profile * */ class ElevationProfilePlotAxis : public QObject { Q_OBJECT private: qreal m_minValue; qreal m_maxValue; qreal m_displayScale; int m_pixelLength; int m_minTickCount; int m_maxTickCount; QString m_unitString; AxisTickList m_ticks; void updateTicks(); void updateScale(); public: explicit ElevationProfilePlotAxis( ); void setRange(qreal minValue, qreal maxValue); void setLength(int length); void setTickCount( const int min, const int max ); void update(); qreal minValue() const; qreal maxValue() const; qreal range() const; qreal scale() const; QString unit() const; AxisTickList ticks() const; }; } Q_DECLARE_TYPEINFO(Marble::AxisTick, Q_PRIMITIVE_TYPE); #endif // ELEVATIONPROFILEPLOTAXIS_H diff --git a/src/plugins/runner/osm/OsmRelation.h b/src/plugins/runner/osm/OsmRelation.h index 2b5538e14..9aa87420c 100644 --- a/src/plugins/runner/osm/OsmRelation.h +++ b/src/plugins/runner/osm/OsmRelation.h @@ -1,61 +1,61 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2015 Dennis Nienhüser // #ifndef MARBLE_OSMRELATION #define MARBLE_OSMRELATION #include "OsmNode.h" #include "OsmWay.h" #include #include #include #include #include namespace Marble { class GeoDataDocument; class OsmRelation { public: OsmPlacemarkData & osmData(); void parseMember(const QXmlStreamAttributes &attributes); void addMember(qint64 reference, const QString &role, const QString &type); void createMultipolygon(GeoDataDocument* document, OsmWays &ways, const OsmNodes &nodes, QSet &usedNodes, QSet &usedWays) const; void createRelation(GeoDataDocument* document, const QHash& wayPlacemarks) const; const OsmPlacemarkData & osmData() const; private: typedef QPair OsmRing; - typedef QVector OsmRings; + using OsmRings = QVector; struct OsmMember { QString type; QString role; qint64 reference; OsmMember(); }; OsmRings rings(const QStringList &roles, const OsmWays &ways, const OsmNodes &nodes, QSet &usedNodes, QSet &usedWays) const; OsmPlacemarkData m_osmData; QVector m_members; }; typedef QHash OsmRelations; } #endif diff --git a/src/plugins/runner/osm/translators/OsmConverter.h b/src/plugins/runner/osm/translators/OsmConverter.h index 585a92122..ce2763f8c 100644 --- a/src/plugins/runner/osm/translators/OsmConverter.h +++ b/src/plugins/runner/osm/translators/OsmConverter.h @@ -1,61 +1,61 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Dennis Nienhüser // #ifndef MARBLE_OSMCONVERTER_H #define MARBLE_OSMCONVERTER_H #include namespace Marble { class GeoDataLineString; class GeoDataDocument; class GeoDataLinearRing; class GeoDataPolygon; class GeoDataPlacemark; class GeoDataFeature; class OsmPlacemarkData; class OsmConverter { public: typedef QPair Tag; typedef QPair Node; typedef QPair Way; typedef QPair Relation; - typedef QVector Nodes; - typedef QVector Tags; - typedef QVector Ways; - typedef QVector Relations; + using Nodes = QVector; + using Tags = QVector; + using Ways = QVector; + using Relations = QVector; void read(const GeoDataDocument* document); const Nodes & nodes() const; const Ways & ways() const; const Relations &relations() const; private: Nodes m_nodes; Ways m_ways; Relations m_relations; void processLinearRing(GeoDataLinearRing *linearRing, const OsmPlacemarkData& osmData); void processPolygon(GeoDataPolygon *polygon, const OsmPlacemarkData& osmData, GeoDataPlacemark* placemark); }; } #endif diff --git a/tools/osm-addresses/OsmParser.cpp b/tools/osm-addresses/OsmParser.cpp index 762794f25..05a7cb4a2 100644 --- a/tools/osm-addresses/OsmParser.cpp +++ b/tools/osm-addresses/OsmParser.cpp @@ -1,760 +1,760 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2011 Dennis Nienhüser // #include "OsmParser.h" #include "OsmRegionTree.h" #include "GeoDataLatLonAltBox.h" #include "GeoDataLinearRing.h" #include "GeoDataLineString.h" #include "GeoDataPolygon.h" #include "GeoDataDocument.h" #include "GeoDataPlacemark.h" #include "GeoDataMultiGeometry.h" #include "GeoDataStyle.h" #include "GeoDataStyleMap.h" #include "GeoDataLineStyle.h" #include "geodata/writer/GeoDataDocumentWriter.h" #include #include #include #include #include namespace Marble { using namespace Oxygen; namespace { struct GrahamScanHelper { Coordinate coordinate; qreal direction; GrahamScanHelper( const Coordinate &coordinate_=Coordinate(), qreal direction_=0.0 ) : coordinate( coordinate_ ), direction( direction_ ) { // nothing to do } double turnDirection( const GrahamScanHelper &two, const GrahamScanHelper &three ) { return ( two.coordinate.lat - coordinate.lat ) * ( three.coordinate.lon - coordinate.lon ) - ( two.coordinate.lon - coordinate.lon ) * ( three.coordinate.lat - coordinate.lat ); } static bool directionLessThan( const GrahamScanHelper &one, const GrahamScanHelper &two ) { return one.direction < two.direction; } }; } bool moreImportantAdminArea( const OsmRegion &a, const OsmRegion& b ) { return a.adminLevel() < b.adminLevel(); } OsmParser::OsmParser( QObject *parent ) : QObject( parent ), m_convexHull( nullptr ) { m_categoryMap["tourism/camp_site"] = OsmPlacemark::AccomodationCamping; m_categoryMap["tourism/hostel"] = OsmPlacemark::AccomodationHostel; m_categoryMap["tourism/hotel"] = OsmPlacemark::AccomodationHotel; m_categoryMap["tourism/motel"] = OsmPlacemark::AccomodationMotel; //m_categoryMap["/"] = OsmPlacemark::AccomodationYouthHostel; m_categoryMap["amenity/library"] = OsmPlacemark::AmenityLibrary; m_categoryMap["amenity/college"] = OsmPlacemark::EducationCollege; m_categoryMap["amenity/school"] = OsmPlacemark::EducationSchool; m_categoryMap["amenity/university"] = OsmPlacemark::EducationUniversity; m_categoryMap["amenity/bar"] = OsmPlacemark::FoodBar; m_categoryMap["amenity/biergarten"] = OsmPlacemark::FoodBiergarten; m_categoryMap["amenity/cafe"] = OsmPlacemark::FoodCafe; m_categoryMap["amenity/fast_food"] = OsmPlacemark::FoodFastFood; m_categoryMap["amenity/pub"] = OsmPlacemark::FoodPub; m_categoryMap["amenity/restaurant"] = OsmPlacemark::FoodRestaurant; m_categoryMap["amenity/doctor"] = OsmPlacemark::HealthDoctors; m_categoryMap["amenity/doctors"] = OsmPlacemark::HealthDoctors; m_categoryMap["amenity/hospital"] = OsmPlacemark::HealthHospital; m_categoryMap["amenity/pharmacy"] = OsmPlacemark::HealthPharmacy; m_categoryMap["amenity/atm"] = OsmPlacemark::MoneyAtm; m_categoryMap["amenity/bank"] = OsmPlacemark::MoneyBank; m_categoryMap["shop/beverages"] = OsmPlacemark::ShoppingBeverages; m_categoryMap["shop/hifi"] = OsmPlacemark::ShoppingHifi; m_categoryMap["shop/supermarket"] = OsmPlacemark::ShoppingSupermarket; m_categoryMap["tourism/attraction"] = OsmPlacemark::TouristAttraction; m_categoryMap["tourism/castle"] = OsmPlacemark::TouristCastle; m_categoryMap["amenity/cinema"] = OsmPlacemark::TouristCinema; m_categoryMap["tourism/monument"] = OsmPlacemark::TouristMonument; m_categoryMap["tourism/museum"] = OsmPlacemark::TouristMuseum; m_categoryMap["historic/ruins"] = OsmPlacemark::TouristRuin; m_categoryMap["amenity/theatre"] = OsmPlacemark::TouristTheatre; m_categoryMap["tourism/theme_park"] = OsmPlacemark::TouristThemePark; m_categoryMap["tourism/viewpoint"] = OsmPlacemark::TouristViewPoint; m_categoryMap["tourism/zoo"] = OsmPlacemark::TouristZoo; m_categoryMap["aeroway/aerodrome"] = OsmPlacemark::TransportAirport; m_categoryMap["aeroway/terminal"] = OsmPlacemark::TransportAirportTerminal; m_categoryMap["amenity/bus_station"] = OsmPlacemark::TransportBusStation; m_categoryMap["highway/bus_stop"] = OsmPlacemark::TransportBusStop; m_categoryMap["highway/speed_camera"] = OsmPlacemark::TransportSpeedCamera; m_categoryMap["amenity/car_sharing"] = OsmPlacemark::TransportCarShare; m_categoryMap["amenity/car_rental"] = OsmPlacemark::TransportRentalCar; m_categoryMap["amenity/bicycle_rental"] = OsmPlacemark::TransportRentalBicycle; m_categoryMap["amenity/fuel"] = OsmPlacemark::TransportFuel; m_categoryMap["amenity/parking"] = OsmPlacemark::TransportParking; m_categoryMap["amenity/taxi"] = OsmPlacemark::TransportTaxiRank; m_categoryMap["railway/station"] = OsmPlacemark::TransportTrainStation; m_categoryMap["railway/tram_stop"] = OsmPlacemark::TransportTramStop; } void OsmParser::addWriter( Writer* writer ) { m_writers.push_back( writer ); } Node::operator OsmPlacemark() const { OsmPlacemark placemark; placemark.setCategory( category ); placemark.setName( name.trimmed() ); placemark.setHouseNumber( houseNumber.trimmed() ); placemark.setLongitude( lon ); placemark.setLatitude( lat ); return placemark; } Node::operator Coordinate() const { Coordinate coordinate; coordinate.lon = lon; coordinate.lat = lat; return coordinate; } Way::operator OsmPlacemark() const { OsmPlacemark placemark; placemark.setCategory( category ); placemark.setName( name.trimmed() ); placemark.setHouseNumber( houseNumber.trimmed() ); return placemark; } void Way::setPosition( const QHash &database, OsmPlacemark &placemark ) const { if ( !nodes.isEmpty() ) { if ( nodes.first() == nodes.last() && database.contains( nodes.first() ) ) { GeoDataLinearRing ring; for( int id: nodes ) { if ( database.contains( id ) ) { const Coordinate &node = database[id]; GeoDataCoordinates coordinates( node.lon, node.lat, 0.0, GeoDataCoordinates::Degree ); ring << coordinates; } else { qDebug() << "Missing node " << id << " in database"; } } if ( !ring.isEmpty() ) { GeoDataCoordinates center = ring.latLonAltBox().center(); placemark.setLongitude( center.longitude( GeoDataCoordinates::Degree ) ); placemark.setLatitude( center.latitude( GeoDataCoordinates::Degree ) ); } } else { int id = nodes.at( nodes.size() / 2 ); if ( database.contains( id ) ) { const Coordinate &node = database[id]; placemark.setLongitude( node.lon ); placemark.setLatitude( node.lat ); } } } } void Way::setRegion( const QHash &database, const OsmRegionTree & tree, QList & osmOsmRegions, OsmPlacemark &placemark ) const { if ( !city.isEmpty() ) { for( const OsmOsmRegion & region: osmOsmRegions ) { if ( region.region.name() == city ) { placemark.setRegionId( region.region.identifier() ); return; } } for( const Node & node: database ) { if ( node.category >= OsmPlacemark::PlacesRegion && node.category <= OsmPlacemark::PlacesIsland && node.name == city ) { qDebug() << "Creating a new implicit region from " << node.name << " at " << node.lon << "," << node.lat; OsmOsmRegion region; region.region.setName( city ); region.region.setLongitude( node.lon ); region.region.setLatitude( node.lat ); placemark.setRegionId( region.region.identifier() ); osmOsmRegions.push_back( region ); return; } } qDebug() << "Unable to locate city " << city << ", setting it up without coordinates"; OsmOsmRegion region; region.region.setName( city ); placemark.setRegionId( region.region.identifier() ); osmOsmRegions.push_back( region ); return; } GeoDataCoordinates position( placemark.longitude(), placemark.latitude(), 0.0, GeoDataCoordinates::Degree ); placemark.setRegionId( tree.smallestRegionId( position ) ); } void OsmParser::read( const QFileInfo &content, const QString &areaName ) { QTime timer; timer.start(); m_nodes.clear(); m_ways.clear(); m_relations.clear(); m_placemarks.clear(); m_osmOsmRegions.clear(); int pass = 0; bool needAnotherPass = false; do { qWarning() << "Step 1." << pass << ": Parsing input file " << content.fileName(); parse( content, pass++, needAnotherPass ); } while ( needAnotherPass ); qWarning() << "Step 2: " << m_coordinates.size() << "coordinates." << "Now extracting regions from" << m_relations.size() << "relations"; QHash::iterator itpoint = m_relations.begin(); QHash::iterator const endpoint = m_relations.end(); for(; itpoint != endpoint; ++itpoint ) { if ( itpoint.value().isAdministrativeBoundary /*&& relation.isMultipolygon*/ ) { importMultipolygon( itpoint.value() ); if ( !itpoint.value().relations.isEmpty() ) { qDebug() << "Ignoring relations inside the relation " << itpoint.value().name; } } } m_relations.clear(); for ( int i = 0; i < m_osmOsmRegions.size(); ++i ) { OsmOsmRegion &osmOsmRegion = m_osmOsmRegions[i]; GeoDataCoordinates center = osmOsmRegion.region.geometry().latLonAltBox().center(); osmOsmRegion.region.setLongitude( center.longitude( GeoDataCoordinates::Degree ) ); osmOsmRegion.region.setLatitude( center.latitude( GeoDataCoordinates::Degree ) ); } qWarning() << "Step 3: Creating region hierarchies from" << m_osmOsmRegions.size() << "administrative boundaries"; QMultiMap sortedRegions; for ( int i = 0; i < m_osmOsmRegions.size(); ++i ) { sortedRegions.insert( m_osmOsmRegions[i].region.adminLevel(), i ); } for ( int i = 0; i < m_osmOsmRegions.size(); ++i ) { GeoDataLinearRing const & ring = m_osmOsmRegions[i].region.geometry().outerBoundary(); OsmOsmRegion* parent = nullptr; qDebug() << "Examining admin region " << i << " of " << m_osmOsmRegions.count(); for ( int level=m_osmOsmRegions[i].region.adminLevel()-1; level >= 0 && parent == nullptr; --level ) { QList candidates = sortedRegions.values( level ); qDebug() << "Examining " << candidates.count() << "admin regions on level" << level; for( int j: candidates ) { GeoDataLinearRing const & outer = m_osmOsmRegions[j].region.geometry().outerBoundary(); if ( contains( outer, ring ) ) { if ( parent == nullptr || contains( parent->region.geometry().outerBoundary(), outer ) ) { qDebug() << "Parent found: " << m_osmOsmRegions[i].region.name() << ", level " << m_osmOsmRegions[i].region.adminLevel() << "is a child of " << m_osmOsmRegions[j].region.name() << ", level " << m_osmOsmRegions[j].region.adminLevel(); parent = &m_osmOsmRegions[j]; break; } } } } m_osmOsmRegions[i].parent = parent; } for ( int i = 0; i < m_osmOsmRegions.size(); ++i ) { int const parent = m_osmOsmRegions[i].parent ? m_osmOsmRegions[i].parent->region.identifier() : 0; m_osmOsmRegions[i].region.setParentIdentifier( parent ); } OsmRegion mainArea; mainArea.setIdentifier( 0 ); mainArea.setName( areaName ); mainArea.setAdminLevel( 1 ); QPair minLon( -180.0, 180.0 ), minLat( -90.0, 90.0 ); for( const Coordinate & node: m_coordinates ) { minLon.first = qMin( node.lon, minLon.first ); minLon.second = qMax( node.lon, minLon.second ); minLat.first = qMin( node.lat, minLat.first ); minLat.second = qMax( node.lat, minLat.second ); } GeoDataLatLonBox center( minLat.second, minLat.first, minLon.second, minLon.first ); mainArea.setLongitude( center.center().longitude( GeoDataCoordinates::Degree ) ); mainArea.setLatitude( center.center().latitude( GeoDataCoordinates::Degree ) ); QList regions; for( const OsmOsmRegion & region: m_osmOsmRegions ) { regions << region.region; } std::sort( regions.begin(), regions.end(), moreImportantAdminArea ); OsmRegionTree regionTree( mainArea ); regionTree.append( regions ); Q_ASSERT( regions.isEmpty() ); int left = 0; regionTree.traverse( left ); qWarning() << "Step 4: Creating placemarks from" << m_nodes.size() << "nodes"; for( const Node & node: m_nodes ) { if ( node.save ) { OsmPlacemark placemark = node; GeoDataCoordinates position( node.lon, node.lat, 0.0, GeoDataCoordinates::Degree ); placemark.setRegionId( regionTree.smallestRegionId( position ) ); if ( !node.name.isEmpty() ) { placemark.setHouseNumber( QString() ); m_placemarks.push_back( placemark ); } if ( !node.street.isEmpty() && node.name != node.street ) { placemark.setCategory( OsmPlacemark::Address ); placemark.setName( node.street.trimmed() ); placemark.setHouseNumber( node.houseNumber.trimmed() ); m_placemarks.push_back( placemark ); } } } qWarning() << "Step 5: Creating placemarks from" << m_ways.size() << "ways"; QMultiMap waysByName; for ( const Way & way: m_ways ) { if ( way.save ) { if ( !way.name.isEmpty() && !way.nodes.isEmpty() ) { waysByName.insert( way.name, way ); } if ( !way.street.isEmpty() && way.name != way.street && !way.nodes.isEmpty() ) { waysByName.insert( way.street, way ); } } else { ++m_statistic.uselessWays; } } QSet keys = QSet::fromList( waysByName.keys() ); for( const QString & key: keys ) { QList > merged = merge( waysByName.values( key ) ); for( const QList & ways: merged ) { Q_ASSERT( !ways.isEmpty() ); OsmPlacemark placemark = ways.first(); ways.first().setPosition( m_coordinates, placemark ); ways.first().setRegion( m_nodes, regionTree, m_osmOsmRegions, placemark ); if ( placemark.category() != OsmPlacemark::Address && !ways.first().name.isEmpty() ) { placemark.setHouseNumber( QString() ); m_placemarks.push_back( placemark ); } if ( !ways.first().isBuilding || !ways.first().houseNumber.isEmpty() ) { placemark.setCategory( OsmPlacemark::Address ); QString name = ways.first().street.isEmpty() ? ways.first().name : ways.first().street; if ( !name.isEmpty() ) { placemark.setName( name.trimmed() ); placemark.setHouseNumber( ways.first().houseNumber.trimmed() ); m_placemarks.push_back( placemark ); } } } } m_convexHull = convexHull(); m_coordinates.clear(); m_nodes.clear(); m_ways.clear(); Q_ASSERT( regions.isEmpty() ); for( const OsmOsmRegion & region: m_osmOsmRegions ) { regions << region.region; } std::sort( regions.begin(), regions.end(), moreImportantAdminArea ); regionTree = OsmRegionTree( mainArea ); regionTree.append( regions ); Q_ASSERT( regions.isEmpty() ); left = 0; regionTree.traverse( left ); regions = regionTree; qWarning() << "Step 6: " << m_statistic.mergedWays << " ways merged," << m_statistic.uselessWays << "useless ways." << "Now serializing" << regions.size() << "regions"; for( const OsmRegion & region: regions ) { for( Writer * writer: m_writers ) { writer->addOsmRegion( region ); } } qWarning() << "Step 7: Serializing" << m_placemarks.size() << "placemarks"; for( const OsmPlacemark & placemark: m_placemarks ) { for( Writer * writer: m_writers ) { Q_ASSERT( !placemark.name().isEmpty() ); writer->addOsmPlacemark( placemark ); } } qWarning() << "Step 8: There is no step 8. Done after " << timer.elapsed() / 1000 << "s."; //writeOutlineKml( areaName ); } QList< QList > OsmParser::merge( const QList &ways ) const { QList mergers; for( const Way & way: ways ) { mergers << WayMerger( way ); } bool moved = false; do { moved = false; for( int i = 0; i < mergers.size(); ++i ) { for ( int j = i + 1; j < mergers.size(); ++j ) { if ( mergers[i].compatible( mergers[j] ) ) { mergers[i].merge( mergers[j] ); moved = true; mergers.removeAt( j ); } } } } while ( moved ); QList< QList > result; for( const WayMerger & merger: mergers ) { result << merger.ways; } m_statistic.mergedWays += ( ways.size() - result.size() ); return result; } void OsmParser::importMultipolygon( const Relation &relation ) { /** @todo: import nodes? What are they used for? */ typedef QPair RelationPair; QVector outer; QVector inner; for( const RelationPair & pair: relation.ways ) { if ( pair.second == Outer ) { importWay( outer, pair.first ); } else if ( pair.second == Inner ) { importWay( inner, pair.first ); } else { qDebug() << "Ignoring way " << pair.first << " with unknown relation role."; } } for( const GeoDataLineString & string: outer ) { if ( string.isEmpty() || !( string.first() == string.last() ) ) { qDebug() << "Ignoring open polygon in relation " << relation.name << ". Check data."; continue; } GeoDataPolygon polygon; polygon.setOuterBoundary(GeoDataLinearRing(string)); Q_ASSERT( polygon.outerBoundary().size() > 0 ); for( const GeoDataLineString & hole: inner ) { if ( contains( polygon.outerBoundary(), hole ) ) { polygon.appendInnerBoundary(GeoDataLinearRing(hole)); } } OsmOsmRegion region; region.region.setName( relation.name ); region.region.setGeometry( polygon ); region.region.setAdminLevel( relation.adminLevel ); qDebug() << "Adding administrative region " << relation.name; m_osmOsmRegions.push_back( region ); } } void OsmParser::importWay( QVector &ways, int id ) { if ( !m_ways.contains( id ) ) { qDebug() << "Skipping unknown way " << id << ". Check data."; return; } GeoDataLineString way; for( int node: m_ways[id].nodes ) { if ( !m_coordinates.contains( node ) ) { qDebug() << "Skipping unknown node " << node << ". Check data."; } else { const Coordinate &nd = m_coordinates[node]; GeoDataCoordinates coordinates( nd.lon, nd.lat, 0.0, GeoDataCoordinates::Degree ); way << coordinates; } } QList remove; do { remove.clear(); for ( int i = 0; i < ways.size(); ++i ) { const GeoDataLineString &existing = ways[i]; if ( existing.first() == way.first() ) { way = reverse( way ) << existing; remove.push_front( i ); } else if ( existing.last() == way.first() ) { GeoDataLineString copy = existing; way = copy << way; remove.push_front( i ); } else if ( existing.first() == way.last() ) { way << existing; remove.push_front( i ); } else if ( existing.last() == way.last() ) { way << reverse( existing ); remove.push_front( i ); } } for( int key: remove ) { ways.remove( key ); } } while ( !remove.isEmpty() ); ways.push_back( way ); } GeoDataLineString OsmParser::reverse( const GeoDataLineString & string ) { GeoDataLineString result; for ( int i = string.size() - 1; i >= 0; --i ) { result << string[i]; } return result; } bool OsmParser::shouldSave( ElementType /*type*/, const QString &key, const QString &value ) { - typedef QList Dictionary; + using Dictionary = QList; static QHash interestingTags; if ( interestingTags.isEmpty() ) { Dictionary highways; highways << "primary" << "secondary" << "tertiary"; highways << "residential" << "unclassified" << "road"; highways << "living_street" << "service" << "track"; highways << "bus_stop" << "platform" << "speed_camera"; interestingTags["highway"] = highways; Dictionary aeroways; aeroways << "aerodrome" << "terminal"; interestingTags["aeroway"] = aeroways; interestingTags["aerialway"] = Dictionary() << "station"; Dictionary leisures; leisures << "sports_centre" << "stadium" << "pitch"; leisures << "park" << "dance"; interestingTags["leisure"] = leisures; Dictionary amenities; amenities << "restaurant" << "food_court" << "fast_food"; amenities << "pub" << "bar" << "cafe"; amenities << "biergarten" << "kindergarten" << "school"; amenities << "college" << "university" << "library"; amenities << "ferry_terminal" << "bus_station" << "car_rental"; amenities << "car_sharing" << "fuel" << "parking"; amenities << "bank" << "pharmacy" << "hospital"; amenities << "cinema" << "nightclub" << "theatre"; amenities << "taxi" << "bicycle_rental" << "atm"; interestingTags["amenity"] = amenities; Dictionary shops; shops << "beverages" << "supermarket" << "hifi"; interestingTags["shop"] = shops; Dictionary tourism; tourism << "attraction" << "camp_site" << "caravan_site"; tourism << "chalet" << "chalet" << "hostel"; tourism << "hotel" << "motel" << "museum"; tourism << "theme_park" << "viewpoint" << "zoo"; interestingTags["tourism"] = tourism; Dictionary historic; historic << "castle" << "fort" << "monument"; historic << "ruins"; interestingTags["historic"] = historic; Dictionary railway; railway << "station" << "tram_stop"; interestingTags["railway"] = railway; Dictionary places; places << "region" << "county" << "city"; places << "town" << "village" << "hamlet"; places << "isolated_dwelling" << "suburb" << "locality"; places << "island"; interestingTags["place"] = places; } return interestingTags.contains( key ) && interestingTags[key].contains( value ); } void OsmParser::setCategory( Element &element, const QString &key, const QString &value ) { QString const term = key + QLatin1Char('/') + value; if ( m_categoryMap.contains( term ) ) { if ( element.category != OsmPlacemark::UnknownCategory ) { qDebug() << "Overwriting category " << element.category << " with " << m_categoryMap[term] << " for " << element.name; } element.category = m_categoryMap[term]; } } // From http://en.wikipedia.org/wiki/Graham_scan#Pseudocode GeoDataLinearRing* OsmParser::convexHull() const { Q_ASSERT(m_coordinates.size()>2); QList coordinates = m_coordinates.values(); QVector points; points.reserve( coordinates.size()+1 ); Coordinate start = coordinates.first(); int startPos = 0; for ( int i=0; i2 ); qSwap( points[1], points[startPos] ); Q_ASSERT( start.lat != 360.0 ); for ( int i=0; i 0 ); Q_ASSERT( m <= n ); Q_ASSERT( i >= 0 ); Q_ASSERT( i <= n ); } ++m; qSwap( points[m], points[i] ); } GeoDataLinearRing* ring = new GeoDataLinearRing; for ( int i=1; i<=m; ++i ) { ring->append(GeoDataCoordinates(points[i].coordinate.lon, points[i].coordinate.lat, 0.0, GeoDataCoordinates::Degree)); } return ring; } QColor OsmParser::randomColor() const { QVector colors = QVector() << aluminumGray4 << brickRed4; colors << woodBrown4 << forestGreen4 << hotOrange4; colors << seaBlue2 << skyBlue4 << sunYellow6; return colors.at( qrand() % colors.size() ); } void OsmParser::writeKml( const QString &area, const QString &version, const QString &date, const QString &transport, const QString &payload, const QString &filename ) const { GeoDataDocument* document = new GeoDataDocument; //for( const OsmOsmRegion & region: m_osmOsmRegions ) { GeoDataPlacemark* placemark = new GeoDataPlacemark; placemark->setName( area ); if ( !version.isEmpty() ) { placemark->extendedData().addValue( GeoDataData( "version", version ) ); } if ( !date.isEmpty() ) { placemark->extendedData().addValue( GeoDataData( "date", date ) ); } if ( !transport.isEmpty() ) { placemark->extendedData().addValue( GeoDataData( "transport", transport ) ); } if ( !payload.isEmpty() ) { placemark->extendedData().addValue( GeoDataData( "payload", payload ) ); } GeoDataStyle::Ptr style(new GeoDataStyle); GeoDataLineStyle lineStyle; QColor color = randomColor(); color.setAlpha( 200 ); lineStyle.setColor( color ); lineStyle.setWidth( 4 ); style->setLineStyle( lineStyle ); style->setId(color.name().replace(QLatin1Char('#'), QLatin1Char('f'))); GeoDataStyleMap styleMap; styleMap.setId(color.name().replace(QLatin1Char('#'), QLatin1Char('f'))); styleMap.insert("normal", QLatin1Char('#') + style->id()); document->addStyle( style ); placemark->setStyleUrl(QLatin1Char('#') + styleMap.id()); //placemark->setGeometry( new GeoDataLinearRing( region.region.geometry().outerBoundary() ) ); GeoDataMultiGeometry *geometry = new GeoDataMultiGeometry; geometry->append( m_convexHull ); placemark->setGeometry( geometry ); document->append( placemark ); document->addStyleMap( styleMap ); // } if (!GeoDataDocumentWriter::write(filename, *document)) { qCritical() << "Can not write to " << filename; } } Coordinate::Coordinate(float lon_, float lat_) : lon(lon_), lat(lat_) { // nothing to do } } #include "moc_OsmParser.cpp" diff --git a/tools/vectorosm-tilecreator/NodeReducer.cpp b/tools/vectorosm-tilecreator/NodeReducer.cpp index 9e5b72d4e..42c0a8132 100644 --- a/tools/vectorosm-tilecreator/NodeReducer.cpp +++ b/tools/vectorosm-tilecreator/NodeReducer.cpp @@ -1,220 +1,220 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Akshat Tandon // #include "GeoDataPlacemark.h" #include "GeoDataLineString.h" #include "GeoDataPolygon.h" #include "GeoDataBuilding.h" #include "GeoDataMultiGeometry.h" #include "GeoDataCoordinates.h" #include "MarbleMath.h" #include "NodeReducer.h" #include "OsmPlacemarkData.h" #include #include namespace Marble { NodeReducer::NodeReducer(GeoDataDocument* document, const TileId &tileId) : m_removedNodes(0), m_remainingNodes(0), m_zoomLevel(tileId.zoomLevel()) { const GeoSceneMercatorTileProjection tileProjection; GeoDataLatLonBox tileBoundary = tileProjection.geoCoordinates(m_zoomLevel, tileId.x(), tileId.y()); tileBoundary.scale(1.0-1e-4, 1.0-1e-4); tileBoundary.boundaries(m_tileBoundary[North], m_tileBoundary[South], m_tileBoundary[East], m_tileBoundary[West]); for (GeoDataPlacemark* placemark: document->placemarkList()) { GeoDataGeometry const * const geometry = placemark->geometry(); auto const visualCategory = placemark->visualCategory(); if (const auto prevLine = geodata_cast(geometry)) { GeoDataLineString* reducedLine = new GeoDataLineString; reduce(*prevLine, placemark->osmData(), visualCategory, reducedLine); placemark->setGeometry(reducedLine); } else if (m_zoomLevel < 17) { if (const auto prevRing = geodata_cast(geometry)) { placemark->setGeometry(reducedRing(*prevRing, placemark, visualCategory)); } else if (const auto prevPolygon = geodata_cast(geometry)) { placemark->setGeometry(reducedPolygon(*prevPolygon, placemark, visualCategory)); } else if (const auto building = geodata_cast(geometry)) { if (const auto prevRing = geodata_cast(&building->multiGeometry()->at(0))) { GeoDataLinearRing* ring = reducedRing(*prevRing, placemark, visualCategory); GeoDataBuilding* newBuilding = new GeoDataBuilding(*building); newBuilding->multiGeometry()->clear(); newBuilding->multiGeometry()->append(ring); placemark->setGeometry(newBuilding); } else if (const auto prevPolygon = geodata_cast(&building->multiGeometry()->at(0))) { GeoDataPolygon* poly = reducedPolygon(*prevPolygon, placemark, visualCategory); GeoDataBuilding* newBuilding = new GeoDataBuilding(*building); newBuilding->multiGeometry()->clear(); newBuilding->multiGeometry()->append(poly); placemark->setGeometry(newBuilding); } } } } } qint64 NodeReducer::remainingNodes() const { return m_remainingNodes; } qreal NodeReducer::epsilonFor(qreal multiplier) const { if (m_zoomLevel >= 17) { return 0.25; } else if (m_zoomLevel >= 10) { int const factor = 1 << (qAbs(m_zoomLevel-12)); return multiplier / factor; } else { int const factor = 1 << (qAbs(m_zoomLevel-10)); return multiplier * factor; } } qreal NodeReducer::perpendicularDistance(const GeoDataCoordinates &a, const GeoDataCoordinates &b, const GeoDataCoordinates &c) const { qreal ret; qreal const y0 = a.latitude(); qreal const x0 = a.longitude(); qreal const y1 = b.latitude(); qreal const x1 = b.longitude(); qreal const y2 = c.latitude(); qreal const x2 = c.longitude(); qreal const y01 = x0 - x1; qreal const x01 = y0 - y1; qreal const y10 = x1 - x0; qreal const x10 = y1 - y0; qreal const y21 = x2 - x1; qreal const x21 = y2 - y1; qreal const len = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); qreal const t = len == 0.0 ? -1.0 : (x01 * x21 + y01 * y21) / len; if ( t < 0.0 ) { ret = EARTH_RADIUS * a.sphericalDistanceTo(b); } else if ( t > 1.0 ) { ret = EARTH_RADIUS * a.sphericalDistanceTo(c); } else { qreal const nom = qAbs( x21 * y10 - x10 * y21 ); qreal const den = sqrt( x21 * x21 + y21 * y21 ); ret = EARTH_RADIUS * nom / den; } return ret; } bool NodeReducer::touchesTileBorder(const GeoDataCoordinates &coordinates) const { return coordinates.latitude() >= m_tileBoundary[North] || coordinates.latitude() <= m_tileBoundary[South] || coordinates.longitude() <= m_tileBoundary[West] || coordinates.longitude() >= m_tileBoundary[East]; } qint64 NodeReducer::removedNodes() const { return m_removedNodes; } void NodeReducer::setBorderPoints(OsmPlacemarkData &osmData, const QVector &borderPoints, int length) const { int const n = borderPoints.size(); if (n == 0) { return; } if (n > length) { qDebug() << "Invalid border points for length" << length << ":" << borderPoints; return; } typedef QPair Segment; - typedef QVector Segments; + using Segments = QVector; Segments segments; Segment currentSegment; currentSegment.first = borderPoints.first(); currentSegment.second = currentSegment.first; for (int i=1; i 1 && segments.last().second+1 == length && segments.first().first == 0) { segments.last().second = segments.first().second; segments.pop_front(); } int wraps = 0; for (auto const &segment: segments) { if (segment.first >= segment.second) { ++wraps; } if (segment.first < 0 || segment.second < 0 || segment.first+1 > length || segment.second+1 > length) { qDebug() << "Wrong border points sequence for length " << length << ":" << borderPoints << ", intermediate " << segments; return; } } if (wraps > 1) { //qDebug() << "Wrong border points sequence:" << borderPoints; return; } QString value; value.reserve(segments.size() * (2 + QString::number(length).size())); for (auto const &segment: segments) { int diff = segment.second - segment.first; diff = diff > 0 ? diff : length + diff; value = value % QStringLiteral(";") % QString::number(segment.first) % QStringLiteral("+") % QString::number(diff); } osmData.addTag(QStringLiteral("mx:bp"), value.mid(1)); } GeoDataLinearRing *NodeReducer::reducedRing(const GeoDataLinearRing& prevRing, GeoDataPlacemark* placemark, const GeoDataPlacemark::GeoDataVisualCategory& visualCategory) { GeoDataLinearRing* reducedRing = new GeoDataLinearRing; reduce(prevRing, placemark->osmData(), visualCategory, reducedRing); return reducedRing; } GeoDataPolygon *NodeReducer::reducedPolygon(const GeoDataPolygon& prevPolygon, GeoDataPlacemark* placemark, const GeoDataPlacemark::GeoDataVisualCategory& visualCategory) { GeoDataPolygon* reducedPolygon = new GeoDataPolygon; GeoDataLinearRing const * prevRing = &(prevPolygon.outerBoundary()); GeoDataLinearRing reducedRing; reduce(*prevRing, placemark->osmData().memberReference(-1), visualCategory, &reducedRing); reducedPolygon->setOuterBoundary(reducedRing); QVector const & innerBoundaries = prevPolygon.innerBoundaries(); for(int i = 0; i < innerBoundaries.size(); i++) { prevRing = &innerBoundaries[i]; GeoDataLinearRing reducedInnerRing; reduce(*prevRing, placemark->osmData().memberReference(i), visualCategory, &reducedInnerRing); reducedPolygon->appendInnerBoundary(reducedInnerRing); } return reducedPolygon; } } diff --git a/tools/vectorosm-tilecreator/PeakAnalyzer.h b/tools/vectorosm-tilecreator/PeakAnalyzer.h index 2513a9b0f..2c17295b7 100644 --- a/tools/vectorosm-tilecreator/PeakAnalyzer.h +++ b/tools/vectorosm-tilecreator/PeakAnalyzer.h @@ -1,31 +1,31 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Dennis Nienhüser // #include namespace Marble { class GeoDataPlacemark; class PeakAnalyzer { public: static void determineZoomLevel(const QVector &placemarks); private: - typedef QVector Peaks; - typedef QVector PeakCluster; - typedef QVector PeakClusters; + using Peaks = QVector; + using PeakCluster = QVector; + using PeakClusters = QVector; static Peaks peaksNear(const GeoDataPlacemark* placemark, const Peaks &peaks, double maxDistance); static void dbScan(const Peaks &peaks, double maxDistance, int minPoints); }; } diff --git a/tools/vectorosm-tilecreator/TagsFilter.h b/tools/vectorosm-tilecreator/TagsFilter.h index 4821a454d..4135cda93 100644 --- a/tools/vectorosm-tilecreator/TagsFilter.h +++ b/tools/vectorosm-tilecreator/TagsFilter.h @@ -1,56 +1,56 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Akshat Tandon // #ifndef MARBLE_TAGSFILTER_H #define MARBLE_TAGSFILTER_H #include "OsmPlacemarkData.h" #include #include namespace Marble { class GeoDataDocument; class GeoDataFeature; class TagsFilter { public: typedef QPair Tag; - typedef QVector Tags; + using Tags = QVector; enum FilterFlag { NoFlag = 0, FilterRailwayService }; //Filters placemarks which have tags in the hash TagsFilter(GeoDataDocument* document, const Tags& tagsList, FilterFlag filterFlag = NoFlag); ~TagsFilter(); QVector::const_iterator rejectedObjectsBegin() const; QVector::const_iterator rejectedObjectsEnd() const; GeoDataDocument* accepted(); static void removeAnnotationTags(GeoDataDocument* document); private: static void removeAnnotationTags(OsmPlacemarkData &osmData); GeoDataDocument* m_accepted; QVector m_rejectedObjects; }; } #endif diff --git a/tools/vectorosm-tilecreator/TileIterator.h b/tools/vectorosm-tilecreator/TileIterator.h index 3f157acff..5094504de 100644 --- a/tools/vectorosm-tilecreator/TileIterator.h +++ b/tools/vectorosm-tilecreator/TileIterator.h @@ -1,45 +1,45 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Dennis Nienhüser // #ifndef MARBLE_TILEITERATOR_H #define MARBLE_TILEITERATOR_H #include "GeoDataLatLonBox.h" #include namespace Marble { class TileIterator { public: - typedef TileIterator const_iterator; + using const_iterator = TileIterator; const const_iterator& operator*(); bool operator!=( const const_iterator& ) const; const_iterator& operator++(); const_iterator begin() const; const_iterator end() const; TileIterator(const GeoDataLatLonBox &latLonBox, int zoomLevel); int x() const; int y() const; int total() const; private: TileIterator(); QRect m_bounds; QPoint m_state; static const_iterator const s_end; }; } #endif diff --git a/tools/vectorosm-tilecreator/WayChunk.h b/tools/vectorosm-tilecreator/WayChunk.h index f2384af4b..46033e065 100644 --- a/tools/vectorosm-tilecreator/WayChunk.h +++ b/tools/vectorosm-tilecreator/WayChunk.h @@ -1,61 +1,61 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Akshat Tandon // #ifndef MARBLE_WAYCHUNK_H #define MARBLE_WAYCHUNK_H #include "GeoDataPlacemark.h" #include #include namespace Marble { class GeoDataPlacemark; class WayChunk { private: - typedef QSharedPointer PlacemarkPtr; + using PlacemarkPtr = QSharedPointer; public: - typedef QSharedPointer Ptr; + using Ptr = QSharedPointer; WayChunk(const PlacemarkPtr &placemark, qint64 first, qint64 last ); ~WayChunk(); void append(const PlacemarkPtr &placemark, qint64 last); void append(const Ptr &chunk); void prepend(const PlacemarkPtr & placemark, qint64 first); /* * Creates a new placemark object by concatenating all the linsetrings which exist in the WayChunk * Caller has the responsibility of deleting the object. */ PlacemarkPtr merge(); qint64 first() const; qint64 last() const; void reverse(); int size() const; bool concatPossible(const GeoDataPlacemark &placemark) const; private: bool isTunnel(const OsmPlacemarkData &osmData) const; QVector m_wayList; qint64 m_first; qint64 m_last; GeoDataPlacemark::GeoDataVisualCategory m_visualCategory; bool m_isTunnel; }; } #endif diff --git a/tools/vectorosm-tilecreator/WayConcatenator.cpp b/tools/vectorosm-tilecreator/WayConcatenator.cpp index 7e1a31f44..d2ceb7b0c 100644 --- a/tools/vectorosm-tilecreator/WayConcatenator.cpp +++ b/tools/vectorosm-tilecreator/WayConcatenator.cpp @@ -1,242 +1,242 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Akshat Tandon // #include #include #include #include "GeoDataPlacemark.h" #include "GeoDataDocument.h" #include "GeoDataObject.h" #include "GeoDataLineString.h" #include "OsmPlacemarkData.h" #include "StyleBuilder.h" #include "OsmObjectManager.h" #include "WayConcatenator.h" #include "WayChunk.h" #include "TagsFilter.h" namespace Marble { WayConcatenator::WayConcatenator(GeoDataDocument *document) : m_originalWays(0), m_mergedWays(0) { - typedef QSharedPointer PlacemarkPtr; + using PlacemarkPtr = QSharedPointer; for (GeoDataFeature *feature: document->featureList()) { if (const auto original = geodata_cast(feature)) { bool isWay = false; if (geodata_cast(original->geometry())) { PlacemarkPtr placemark = PlacemarkPtr(new GeoDataPlacemark(*original)); OsmObjectManager::initializeOsmData(placemark.data()); OsmPlacemarkData const & osmData = placemark->osmData(); isWay = osmData.containsTagKey("highway") || osmData.containsTagKey("railway") || osmData.containsTagKey("waterway"); if (isWay) { GeoDataLineString *line = static_cast(placemark->geometry()); qint64 firstId = osmData.nodeReference(line->first()).oid(); qint64 lastId = osmData.nodeReference(line->last()).oid(); if (firstId > 0 && lastId > 0) { ++m_originalWays; bool containsFirst = m_hash.contains(firstId); bool containsLast = m_hash.contains(lastId); if (!containsFirst && !containsLast) { createWayChunk(placemark, firstId, lastId); } else if (containsFirst && !containsLast) { auto chunk = wayChunk(*placemark, firstId); if (chunk != nullptr) { concatFirst(placemark, chunk); } else { createWayChunk(placemark, firstId, lastId); } } else if (!containsFirst && containsLast) { auto chunk = wayChunk(*placemark, lastId); if (chunk != nullptr) { concatLast(placemark, chunk); } else { createWayChunk(placemark, firstId, lastId); } } else if (containsFirst && containsLast) { auto chunk = wayChunk(*placemark, firstId); auto otherChunk = wayChunk(*placemark, lastId); if (chunk != nullptr && otherChunk != nullptr) { if(chunk == otherChunk) { m_wayPlacemarks.append(placemark); } else { concatBoth(placemark, chunk, otherChunk); } } else if(chunk != nullptr && otherChunk == nullptr) { concatFirst(placemark, chunk); } else if(chunk == nullptr && otherChunk != nullptr) { concatLast(placemark, otherChunk); } else { createWayChunk(placemark, firstId, lastId); } } } else { isWay = false; } } } if (!isWay) { m_otherPlacemarks << feature->clone(); } } else { m_otherPlacemarks << feature->clone(); } } document->clear(); for (auto placemark: m_otherPlacemarks) { document->append(placemark); } addWayChunks(document); } int WayConcatenator::originalWays() const { return m_originalWays; } int WayConcatenator::mergedWays() const { return m_mergedWays; } void WayConcatenator::addWayChunks(GeoDataDocument *document) { for (auto const &placemark: m_wayPlacemarks) { document->append(placemark->clone()); } QSet chunkSet; auto itr = m_chunks.begin(); for (; itr != m_chunks.end(); ++itr) { if (!chunkSet.contains(*itr)) { ++m_mergedWays; chunkSet.insert(*itr); PlacemarkPtr placemark = (*itr)->merge(); if (placemark) { document->append(placemark->clone()); } } } m_chunks.clear(); } void WayConcatenator::createWayChunk(const PlacemarkPtr &placemark, qint64 firstId, qint64 lastId) { WayChunk::Ptr chunk = WayChunk::Ptr(new WayChunk(placemark, firstId, lastId)); m_hash.insert(firstId, chunk); if (firstId != lastId) { m_hash.insert(lastId, chunk); } m_chunks.append(chunk); } WayChunk::Ptr WayConcatenator::wayChunk(const GeoDataPlacemark &placemark, qint64 matchId) const { QHash::ConstIterator matchItr = m_hash.find(matchId); while (matchItr != m_hash.end() && matchItr.key() == matchId) { auto const & chunk = matchItr.value(); if (chunk->concatPossible(placemark)) { return chunk; } ++matchItr; } return WayChunk::Ptr(); } void WayConcatenator::concatFirst(const PlacemarkPtr &placemark, const WayChunk::Ptr &chunk) { GeoDataLineString *line = static_cast(placemark->geometry()); qint64 firstId = placemark->osmData().nodeReference(line->first()).oid(); qint64 lastId = placemark->osmData().nodeReference(line->last()).oid(); if (chunk->first() != chunk->last()) { int chunksRemoved = m_hash.remove(firstId, chunk); Q_ASSERT(chunksRemoved == 1); } m_hash.insert(lastId, chunk); if (firstId == chunk->last()) { //First node matches with an existing last node chunk->append(placemark, lastId); } else { //First node matches with an existing first node //Reverse the GeoDataLineString of the placemark line->reverse(); chunk->prepend(placemark, lastId); } } void WayConcatenator::concatLast(const PlacemarkPtr &placemark, const WayChunk::Ptr &chunk) { GeoDataLineString *line = static_cast(placemark->geometry()); qint64 firstId = placemark->osmData().nodeReference(line->first()).oid(); qint64 lastId = placemark->osmData().nodeReference(line->last()).oid(); if (chunk->first() != chunk->last()) { int chunksRemoved = m_hash.remove(lastId, chunk); Q_ASSERT(chunksRemoved == 1); } m_hash.insert(firstId, chunk); if (lastId == chunk->first()) { chunk->prepend(placemark, firstId); } else { line->reverse(); chunk->append(placemark, firstId); } } void WayConcatenator::concatBoth(const PlacemarkPtr &placemark, const WayChunk::Ptr &chunk, const WayChunk::Ptr &otherChunk) { GeoDataLineString *line = static_cast(placemark->geometry()); qint64 firstId = placemark->osmData().nodeReference(line->first()).oid(); qint64 lastId = placemark->osmData().nodeReference(line->last()).oid(); int chunksRemoved; if (chunk->first() != chunk->last()) { chunksRemoved = m_hash.remove(firstId, chunk); Q_ASSERT(chunksRemoved == 1); } if (firstId == chunk->first()) { chunk->reverse(); } chunk->append(placemark, lastId); if (lastId == otherChunk->last()) { otherChunk->reverse(); } chunk->append(otherChunk); chunksRemoved = m_hash.remove(otherChunk->first(), otherChunk); Q_ASSERT(chunksRemoved == 1); if (otherChunk->first() != otherChunk->last()) { chunksRemoved = m_hash.remove(otherChunk->last(), otherChunk); Q_ASSERT(chunksRemoved == 1); } m_hash.insert(otherChunk->last(), chunk); m_chunks.removeOne(otherChunk); } } diff --git a/tools/vectorosm-tilecreator/WayConcatenator.h b/tools/vectorosm-tilecreator/WayConcatenator.h index c0a773687..b28abefe0 100644 --- a/tools/vectorosm-tilecreator/WayConcatenator.h +++ b/tools/vectorosm-tilecreator/WayConcatenator.h @@ -1,49 +1,49 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Akshat Tandon // #ifndef MARBLE_WAYCONCATENATOR_H #define MARBLE_WAYCONCATENATOR_H #include "TagsFilter.h" #include "WayChunk.h" namespace Marble { class WayConcatenator { private: - typedef QSharedPointer PlacemarkPtr; + using PlacemarkPtr = QSharedPointer; public: WayConcatenator(GeoDataDocument *document); int originalWays() const; int mergedWays() const; private: void createWayChunk(const PlacemarkPtr &placemark, qint64 firstId, qint64 lastId); WayChunk::Ptr wayChunk(const GeoDataPlacemark &placemark, qint64 matchId) const; void concatFirst(const PlacemarkPtr &placemark, const WayChunk::Ptr &chunk); void concatLast(const PlacemarkPtr & placemark, const WayChunk::Ptr &chunk); void concatBoth(const PlacemarkPtr &placemark, const WayChunk::Ptr &chunk, const WayChunk::Ptr &otherChunk); void addWayChunks(GeoDataDocument *document); QMultiHash m_hash; QVector m_chunks; QVector m_wayPlacemarks; QVector m_otherPlacemarks; int m_originalWays; int m_mergedWays; }; } #endif diff --git a/tools/vectorosm-tilecreator/clipper/clipper.hpp b/tools/vectorosm-tilecreator/clipper/clipper.hpp index f6ff625c4..96e2fb441 100644 --- a/tools/vectorosm-tilecreator/clipper/clipper.hpp +++ b/tools/vectorosm-tilecreator/clipper/clipper.hpp @@ -1,414 +1,414 @@ /******************************************************************************* * * * Author : Angus Johnson * * Version : 6.4.0 * * Date : 2 July 2015 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2015 * * * * License: * * Use, modification & distribution is subject to Boost Software License Ver 1. * * http://www.boost.org/LICENSE_1_0.txt * * * * Attributions: * * The code in this library is an extension of Bala Vatti's clipping algorithm: * * "A generic solution to polygon clipping" * * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * * http://portal.acm.org/citation.cfm?id=129906 * * * * Computer graphics and geometric modeling: implementation and algorithms * * By Max K. Agoston * * Springer; 1 edition (January 4, 2005) * * http://books.google.com/books?q=vatti+clipping+agoston * * * * See also: * * "Polygon Offsetting by Computing Winding Numbers" * * Paper no. DETC2005-85513 pp. 565-575 * * ASME 2005 International Design Engineering Technical Conferences * * and Computers and Information in Engineering Conference (IDETC/CIE2005) * * September 24-28, 2005 , Long Beach, California, USA * * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * * * *******************************************************************************/ #ifndef clipper_hpp #define clipper_hpp #define CLIPPER_VERSION "6.2.6" //use_int32: When enabled 32bit ints are used instead of 64bit ints. This //improve performance but coordinate values are limited to the range +/- 46340 //#define use_int32 //use_xyz: adds a Z member to IntPoint. Adds a minor cost to performance. //#define use_xyz //use_lines: Enables line clipping. Adds a very minor cost to performance. #define use_lines //use_deprecated: Enables temporary support for the obsolete functions //#define use_deprecated #include #include #include #include #include #include #include #include #include #include namespace ClipperLib { enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; enum PolyType { ptSubject, ptClip }; //By far the most widely used winding rules for polygon filling are //EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) //Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) //see http://glprogramming.com/red/chapter11.html enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; #ifdef use_int32 typedef int cInt; static cInt const loRange = 0x7FFF; static cInt const hiRange = 0x7FFF; #else - typedef signed long long cInt; + using cInt = long long; static cInt const loRange = 0x3FFFFFFF; static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; - typedef signed long long long64; //used by Int128 class - typedef unsigned long long ulong64; + using long64 = long long; //used by Int128 class + using ulong64 = unsigned long long; #endif struct IntPoint { cInt X; cInt Y; constexpr static qint64 const scale = 10000000; #ifdef use_xyz cInt Z; IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {}; #else IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {} IntPoint(const Marble::GeoDataCoordinates* coordinates); #endif friend inline bool operator== (const IntPoint& a, const IntPoint& b) { return a.X == b.X && a.Y == b.Y; } friend inline bool operator!= (const IntPoint& a, const IntPoint& b) { return a.X != b.X || a.Y != b.Y; } Marble::GeoDataCoordinates coordinates() const; bool isInside(const cInt &minX, const cInt &maxX, const cInt &minY, const cInt &maxY) const; private: const Marble::GeoDataCoordinates * m_coordinates = nullptr; }; //------------------------------------------------------------------------------ -typedef std::vector< IntPoint > Path; -typedef std::vector< Path > Paths; +using Path = std::vector; +using Paths = std::vector; inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;} inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;} std::ostream& operator <<(std::ostream &s, const IntPoint &p); std::ostream& operator <<(std::ostream &s, const Path &p); std::ostream& operator <<(std::ostream &s, const Paths &p); struct DoublePoint { double X; double Y; DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} DoublePoint(const IntPoint &ip) : X((double)ip.X), Y((double)ip.Y) {} }; //------------------------------------------------------------------------------ #ifdef use_xyz typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt); #endif enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4}; enum JoinType {jtSquare, jtRound, jtMiter}; enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound}; class PolyNode; -typedef std::vector< PolyNode* > PolyNodes; +using PolyNodes = std::vector; class PolyNode { public: PolyNode(); virtual ~PolyNode(){}; Path Contour; PolyNodes Childs; PolyNode* Parent; PolyNode* GetNext() const; bool IsHole() const; bool IsOpen() const; int ChildCount() const; private: unsigned Index; //node index in Parent.Childs bool m_IsOpen; JoinType m_jointype; EndType m_endtype; PolyNode* GetNextSiblingUp() const; void AddChild(PolyNode& child); friend class Clipper; //to access Index friend class ClipperOffset; }; class PolyTree: public PolyNode { public: ~PolyTree() override{Clear();}; PolyNode* GetFirst() const; void Clear(); int Total() const; private: PolyNodes AllNodes; friend class Clipper; //to access AllNodes }; bool Orientation(const Path &poly); double Area(const Path &poly); int PointInPolygon(const IntPoint &pt, const Path &path); void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); void CleanPolygon(Path& poly, double distance = 1.415); void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415); void CleanPolygons(Paths& polys, double distance = 1.415); void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed); void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed); void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution); void PolyTreeToPaths(const PolyTree& polytree, Paths& paths); void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths); void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths); void ReversePath(Path& p); void ReversePaths(Paths& p); struct IntRect { cInt left; cInt top; cInt right; cInt bottom; }; //enums that are used internally ... enum EdgeSide { esLeft = 1, esRight = 2}; //forward declarations (for stuff used internally) ... struct TEdge; struct IntersectNode; struct LocalMinimum; struct OutPt; struct OutRec; struct Join; -typedef std::vector < OutRec* > PolyOutList; -typedef std::vector < TEdge* > EdgeList; -typedef std::vector < Join* > JoinList; -typedef std::vector < IntersectNode* > IntersectList; +using PolyOutList = std::vector; +using EdgeList = std::vector; +using JoinList = std::vector; +using IntersectList = std::vector; //------------------------------------------------------------------------------ //ClipperBase is the ancestor to the Clipper class. It should not be //instantiated directly. This class simply abstracts the conversion of sets of //polygon coordinates into edge objects that are stored in a LocalMinima list. class ClipperBase { public: ClipperBase(); virtual ~ClipperBase(); virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); virtual void Clear(); IntRect GetBounds(); bool PreserveCollinear() {return m_PreserveCollinear;}; void PreserveCollinear(bool value) {m_PreserveCollinear = value;}; protected: void DisposeLocalMinimaList(); TEdge* AddBoundsToLML(TEdge *e, bool IsClosed); virtual void Reset(); TEdge* ProcessBound(TEdge* E, bool IsClockwise); void InsertScanbeam(const cInt Y); bool PopScanbeam(cInt &Y); bool LocalMinimaPending(); bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin); OutRec* CreateOutRec(); void DisposeAllOutRecs(); void DisposeOutRec(PolyOutList::size_type index); void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); void DeleteFromAEL(TEdge *e); void UpdateEdgeIntoAEL(TEdge *&e); - typedef std::vector MinimaList; + using MinimaList = std::vector; MinimaList::iterator m_CurrentLM; MinimaList m_MinimaList; bool m_UseFullRange; EdgeList m_edges; bool m_PreserveCollinear; bool m_HasOpenPaths; PolyOutList m_PolyOuts; TEdge *m_ActiveEdges; - typedef std::priority_queue ScanbeamList; + using ScanbeamList = std::priority_queue; ScanbeamList m_Scanbeam; }; //------------------------------------------------------------------------------ class Clipper : public virtual ClipperBase { public: Clipper(int initOptions = 0); bool Execute(ClipType clipType, Paths &solution, PolyFillType fillType = pftEvenOdd); bool Execute(ClipType clipType, Paths &solution, PolyFillType subjFillType, PolyFillType clipFillType); bool Execute(ClipType clipType, PolyTree &polytree, PolyFillType fillType = pftEvenOdd); bool Execute(ClipType clipType, PolyTree &polytree, PolyFillType subjFillType, PolyFillType clipFillType); bool ReverseSolution() { return m_ReverseOutput; }; void ReverseSolution(bool value) {m_ReverseOutput = value;}; bool StrictlySimple() {return m_StrictSimple;}; void StrictlySimple(bool value) {m_StrictSimple = value;}; //set the callback function for z value filling on intersections (otherwise Z is 0) #ifdef use_xyz void ZFillFunction(ZFillCallback zFillFunc); #endif protected: virtual bool ExecuteInternal(); private: JoinList m_Joins; JoinList m_GhostJoins; IntersectList m_IntersectList; ClipType m_ClipType; - typedef std::list MaximaList; + using MaximaList = std::list; MaximaList m_Maxima; TEdge *m_SortedEdges; bool m_ExecuteLocked; PolyFillType m_ClipFillType; PolyFillType m_SubjFillType; bool m_ReverseOutput; bool m_UsingPolyTree; bool m_StrictSimple; #ifdef use_xyz ZFillCallback m_ZFill; //custom callback #endif void SetWindingCount(TEdge& edge); bool IsEvenOddFillType(const TEdge& edge) const; bool IsEvenOddAltFillType(const TEdge& edge) const; void InsertLocalMinimaIntoAEL(const cInt botY); void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge); void AddEdgeToSEL(TEdge *edge); bool PopEdgeFromSEL(TEdge *&edge); void CopyAELToSEL(); void DeleteFromSEL(TEdge *e); void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); bool IsContributing(const TEdge& edge) const; bool IsTopHorz(const cInt XPos); void DoMaxima(TEdge *e); void ProcessHorizontals(); void ProcessHorizontal(TEdge *horzEdge); void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); OutRec* GetOutRec(int idx); void AppendPolygon(TEdge *e1, TEdge *e2); void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt); OutPt* AddOutPt(TEdge *e, const IntPoint &pt); OutPt* GetLastOutPt(TEdge *e); bool ProcessIntersections(const cInt topY); void BuildIntersectList(const cInt topY); void ProcessIntersectList(); void ProcessEdgesAtTopOfScanbeam(const cInt topY); void BuildResult(Paths& polys); void BuildResult2(PolyTree& polytree); void SetHoleState(TEdge *e, OutRec *outrec); void DisposeIntersectNodes(); bool FixupIntersectionOrder(); void FixupOutPolygon(OutRec &outrec); void FixupOutPolyline(OutRec &outrec); bool IsHole(TEdge *e); bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl); void FixHoleLinkage(OutRec &outrec); void AddJoin(OutPt *op1, OutPt *op2, const IntPoint &offPt); void ClearJoins(); void ClearGhostJoins(); void AddGhostJoin(OutPt *op, const IntPoint &offPt); bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2); void JoinCommonEdges(); void DoSimplePolygons(); void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec); void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec); #ifdef use_xyz void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2); #endif }; //------------------------------------------------------------------------------ class ClipperOffset { public: ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25); ~ClipperOffset(); void AddPath(const Path& path, JoinType joinType, EndType endType); void AddPaths(const Paths& paths, JoinType joinType, EndType endType); void Execute(Paths& solution, double delta); void Execute(PolyTree& solution, double delta); void Clear(); double MiterLimit; double ArcTolerance; private: Paths m_destPolys; Path m_srcPoly; Path m_destPoly; std::vector m_normals; double m_delta, m_sinA, m_sin, m_cos; double m_miterLim, m_StepsPerRad; IntPoint m_lowest; PolyNode m_polyNodes; void FixOrientations(); void DoOffset(double delta); void OffsetPoint(int j, int& k, JoinType jointype); void DoSquare(int j, int k); void DoMiter(int j, int k, double r); void DoRound(int j, int k); }; //------------------------------------------------------------------------------ class clipperException : public std::exception { public: clipperException(const char* description): m_descr(description) {} ~clipperException() throw() override {} const char* what() const throw() override {return m_descr.c_str();} private: std::string m_descr; }; //------------------------------------------------------------------------------ } //ClipperLib namespace #endif //clipper_hpp diff --git a/tools/vectorosm-tilecreator/vectorosm-cachetiles.cpp b/tools/vectorosm-tilecreator/vectorosm-cachetiles.cpp index 554820496..2ec56a79b 100644 --- a/tools/vectorosm-tilecreator/vectorosm-cachetiles.cpp +++ b/tools/vectorosm-tilecreator/vectorosm-cachetiles.cpp @@ -1,178 +1,178 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 Dennis Nienhüser // #include "GeoDataDocumentWriter.h" #include "GeoDataGeometry.h" #include "GeoDataLatLonAltBox.h" #include "GeoDataPlacemark.h" #include "GeoDataPolygon.h" #include "MarbleDirs.h" #include "MarbleModel.h" #include "MbTileWriter.h" #include "NodeReducer.h" #include "ParsingRunnerManager.h" #include "TileDirectory.h" #include "TileId.h" #include "VectorClipper.h" #include "WayConcatenator.h" #include "TileQueue.h" #include #include #include #include #include #include #include using namespace Marble; GeoDataDocument* mergeDocuments(GeoDataDocument* map1, GeoDataDocument* map2) { GeoDataDocument* mergedMap = new GeoDataDocument(*map1); OsmPlacemarkData marbleLand; marbleLand.addTag("marble_land","landmass"); for (auto placemark: map2->placemarkList()) { GeoDataPlacemark* land = new GeoDataPlacemark(*placemark); if (geodata_cast(land->geometry())) { land->setOsmData(marbleLand); } mergedMap->append(land); } return mergedMap; } int main(int argc, char *argv[]) { QTime timer; timer.start(); QCoreApplication app(argc, argv); QCoreApplication::setApplicationName("marble-vectorosm-cachetiles"); QCoreApplication::setApplicationVersion("0.1"); QCommandLineParser parser; parser.setApplicationDescription("Create a vectorosm tile and its neighborhood"); parser.addHelpOption(); parser.addVersionOption(); parser.addPositionalArgument("tile", "The tile to create (in z/x/y.extension format)"); parser.addOptions({ {{"c", "cache-directory"}, "Directory for temporary data.", "cache", "cache"}, {{"m", "mbtile"}, "Store tiles in a mbtile database.", "mbtile"}, {"verbose", "Write progress information to standard output."} }); parser.process(app); const QStringList args = parser.positionalArguments(); if (args.size() != 1) { parser.showHelp(); return 0; } auto const input = args.first().split('/'); if (input.size() != 3) { qWarning() << "Tile" << input << "does not match the z/x/y.format convention"; parser.showHelp(); return 1; } bool canParse[] = {false, false, false}; TileId centerTile(0, input[0].toInt(&canParse[0]), input[1].toInt(&canParse[1]), QFileInfo(input[2]).baseName().toInt(&canParse[2])); if (!canParse[0] || !canParse[1] || !canParse[2]) { qWarning() << "Tile" << input << "does not consist of digits in the format z/x/y.format"; parser.showHelp(); return 1; } TileQueue tileQueue; QSet dynamicTiles; tileQueue.read(dynamicTiles); if (dynamicTiles.contains(centerTile)) { return 0; } QString const extension = QFileInfo(input[2]).completeSuffix(); QString const mbtile = parser.value("mbtile"); QSharedPointer mbtileWriter = QSharedPointer(new MbTileWriter(mbtile, extension)); mbtileWriter->setReportProgress(false); mbtileWriter->setCommitInterval(500); MarbleModel model; ParsingRunnerManager manager(model.pluginManager()); QString const cacheDirectory = parser.value("cache-directory"); QDir().mkpath(cacheDirectory); if (!QFileInfo(cacheDirectory).isWritable()) { qWarning() << "Cannot write to cache directory" << cacheDirectory; parser.showHelp(1); } TileDirectory mapTiles(TileDirectory::OpenStreetMap, cacheDirectory, manager, extension, centerTile.zoomLevel()); TileDirectory landTiles(TileDirectory::Landmass, cacheDirectory, manager, extension, centerTile.zoomLevel()); int const offset = 3; int const N = pow(2,centerTile.zoomLevel()); QRect boundaries = QRect(0, 0, N-1, N-1) & QRect(QPoint(centerTile.x()-offset, centerTile.y()-offset), QPoint(centerTile.x()+offset, centerTile.y()+offset)); int count = 0; int const total = boundaries.width() * boundaries.height(); bool const printProgress = parser.isSet("verbose"); for (int x=boundaries.left(); x<=boundaries.right(); ++x) { for (int y=boundaries.top(); y<=boundaries.bottom(); ++y) { auto const tileId = TileId (0, centerTile.zoomLevel(), x, y); ++count; if (mbtileWriter->hasTile(x, y, tileId.zoomLevel())) { continue; } - typedef QSharedPointer GeoDocPtr; + using GeoDocPtr = QSharedPointer; GeoDocPtr tile1 = GeoDocPtr(mapTiles.clip(tileId.zoomLevel(), tileId.x(), tileId.y())); TagsFilter::removeAnnotationTags(tile1.data()); if (tileId.zoomLevel() < 17) { WayConcatenator concatenator(tile1.data()); } NodeReducer nodeReducer(tile1.data(), tileId); GeoDocPtr tile2 = GeoDocPtr(landTiles.clip(tileId.zoomLevel(), tileId.x(), tileId.y())); GeoDocPtr combined = GeoDocPtr(mergeDocuments(tile1.data(), tile2.data())); QBuffer buffer; buffer.open(QBuffer::ReadWrite); if (GeoDataDocumentWriter::write(&buffer, *combined, extension)) { buffer.seek(0); mbtileWriter->addTile(&buffer, tileId.x(), tileId.y(), tileId.zoomLevel()); } else { qWarning() << "Could not write the tile " << combined->name(); } dynamicTiles << tileId; if (printProgress) { TileDirectory::printProgress(qreal(count) / total); std::cout << " Tile " << count << "/" << total << " ("; std::cout << combined->name().toStdString() << ")."; std::cout << std::string(20, ' ') << '\r'; std::cout.flush(); } } } tileQueue.write(dynamicTiles); if (printProgress) { TileDirectory::printProgress(1.0); std::cout << "Vector OSM tiles complete after " << timer.elapsed() << " ms." << std::string(30, ' ') << std::endl; } return 0; } diff --git a/tools/vectorosm-tilecreator/vectorosm-tilecreator.cpp b/tools/vectorosm-tilecreator/vectorosm-tilecreator.cpp index 751596827..5c349773f 100644 --- a/tools/vectorosm-tilecreator/vectorosm-tilecreator.cpp +++ b/tools/vectorosm-tilecreator/vectorosm-tilecreator.cpp @@ -1,348 +1,348 @@ // // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2016 David Kolozsvari // Copyright 2016 Dennis Nienhüser // #include "GeoDataDocumentWriter.h" #include "MarbleModel.h" #include "ParsingRunnerManager.h" #include "GeoDataGeometry.h" #include "GeoDataPlacemark.h" #include "GeoDataPolygon.h" #include "GeoDataLatLonAltBox.h" #include "TileId.h" #include "MarbleDirs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "VectorClipper.h" #include "NodeReducer.h" #include "WayConcatenator.h" #include "TileIterator.h" #include "TileDirectory.h" #include "MbTileWriter.h" #include "SpellChecker.h" #include using namespace Marble; GeoDataDocument* mergeDocuments(GeoDataDocument* map1, GeoDataDocument* map2) { GeoDataDocument* mergedMap = new GeoDataDocument(*map1); OsmPlacemarkData marbleLand; marbleLand.addTag("marble_land","landmass"); for (auto placemark: map2->placemarkList()) { GeoDataPlacemark* land = new GeoDataPlacemark(*placemark); if (geodata_cast(land->geometry())) { land->setOsmData(marbleLand); } mergedMap->append(land); } return mergedMap; } QString tileFileName(const QCommandLineParser &parser, int x, int y, int zoomLevel) { QString const extension = parser.value("extension"); QString const output = parser.isSet("development") ? QString("%1/maps/earth/vectorosm-dev").arg(MarbleDirs::localPath()) : parser.value("output"); QString const outputDir = QString("%1/%2/%3").arg(output).arg(zoomLevel).arg(x); QString const outputFile = QString("%1/%2.%3").arg(outputDir).arg(y).arg(extension); return outputFile; } void writeBoundaryTile(GeoDataDocument* tile, const QString ®ion, const QCommandLineParser &parser, int x, int y, int zoomLevel) { QString const extension = parser.value("extension"); QString const outputDir = QString("%1/boundaries/%2/%3/%4").arg(parser.value("cache-directory")).arg(region).arg(zoomLevel).arg(x); QString const outputFile = QString("%1/%2.%3").arg(outputDir).arg(y).arg(extension); QDir().mkpath(outputDir); GeoDataDocumentWriter::write(outputFile, *tile); } QSharedPointer mergeBoundaryTiles(const QSharedPointer &background, ParsingRunnerManager &manager, const QCommandLineParser &parser, int x, int y, int zoomLevel) { GeoDataDocument* mergedMap = new GeoDataDocument; OsmPlacemarkData marbleLand; marbleLand.addTag("marble_land","landmass"); for (auto placemark: background->placemarkList()) { GeoDataPlacemark* land = new GeoDataPlacemark(*placemark); if (geodata_cast(land->geometry())) { land->setOsmData(marbleLand); } mergedMap->append(land); } QString const extension = parser.value("extension"); QString const boundaryDir = QString("%1/boundaries").arg(parser.value("cache-directory")); for(auto const &dir: QDir(boundaryDir).entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { QString const file = QString("%1/%2/%3/%4/%5.%6").arg(boundaryDir).arg(dir).arg(zoomLevel).arg(x).arg(y).arg(extension); if (QFileInfo(file).exists()) { auto tile = TileDirectory::open(file, manager); if (tile) { for (auto placemark: tile->placemarkList()) { mergedMap->append(placemark->clone()); } } } } return QSharedPointer(mergedMap); } bool writeTile(GeoDataDocument* tile, const QString &outputFile) { QDir().mkpath(QFileInfo(outputFile).path()); if (!GeoDataDocumentWriter::write(outputFile, *tile)) { qWarning() << "Could not write the file " << outputFile; return false; } return true; } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QCoreApplication::setApplicationName("marble-vectorosm-tilecreator"); QCoreApplication::setApplicationVersion("0.1"); QCommandLineParser parser; parser.setApplicationDescription("A tool for Marble, which is used to reduce the details of osm maps."); parser.addHelpOption(); parser.addVersionOption(); parser.addPositionalArgument("input", "The input .osm or .shp file."); parser.addOptions({ {{"t", "osmconvert"}, "Tile data using osmconvert."}, {"conflict-resolution", "How to deal with existing tiles: overwrite, skip or merge", "mode", "overwrite"}, {{"c", "cache-directory"}, "Directory for temporary data.", "cache", "cache"}, {{"m", "mbtile"}, "Store tiles at level 15 onwards in a mbtile database.", "mbtile"}, {{"s", "spellcheck"}, "Use this geonames.org cities file for spell-checking city names", "spellcheck"}, {"verbose", "Increase amount of shell output information"}, {"boundaries", "Write boundary tiles (implied by conflict-resolution=merge)"}, {{"d", "development"}, "Use local development vector osm map theme as output storage"}, {{"z", "zoom-level"}, "Zoom level according to which OSM information has to be processed.", "levels", "11,13,15,17"}, {{"o", "output"}, "Output file or directory", "output", QString("%1/maps/earth/vectorosm").arg(MarbleDirs::localPath())}, {{"e", "extension"}, "Output file type: o5m (default), osm or kml", "file extension", "o5m"} }); // Process the actual command line arguments given by the user parser.process(app); const QStringList args = parser.positionalArguments(); if (args.isEmpty()) { parser.showHelp(); return 0; } // input is args.at(0), output is args.at(1) QString const extension = parser.value("extension"); QString inputFileName = args.at(0); auto const levels = parser.value("zoom-level").split(','); QVector zoomLevels; int maxZoomLevel = 0; for(auto const &level: levels) { int const zoomLevel = level.toInt(); maxZoomLevel = qMax(zoomLevel, maxZoomLevel); zoomLevels << zoomLevel; } if (zoomLevels.isEmpty()) { parser.showHelp(1); return 1; } bool const overwriteTiles = parser.value("conflict-resolution") == "overwrite"; bool const mergeTiles = parser.value("conflict-resolution") == "merge"; bool const writeBoundaries = mergeTiles || parser.isSet("boundaries"); QSharedPointer mbtileWriter; if (parser.isSet("mbtile")) { QString const mbtile = parser.value("mbtile"); mbtileWriter = QSharedPointer(new MbTileWriter(mbtile, extension)); mbtileWriter->setReportProgress(false); mbtileWriter->setCommitInterval(500); } MarbleModel model; ParsingRunnerManager manager(model.pluginManager()); QString const cacheDirectory = parser.value("cache-directory"); QDir().mkpath(cacheDirectory); if (!QFileInfo(cacheDirectory).isWritable()) { qWarning() << "Cannot write to cache directory" << cacheDirectory; parser.showHelp(1); } if (*zoomLevels.cbegin() <= 9) { auto map = TileDirectory::open(inputFileName, manager); VectorClipper processor(map.data(), maxZoomLevel); GeoDataLatLonBox world(85.0, -85.0, 180.0, -180.0, GeoDataCoordinates::Degree); if (parser.isSet("spellcheck")) { SpellChecker spellChecker(parser.value("spellcheck")); spellChecker.setVerbose(parser.isSet("verbose")); spellChecker.correctPlaceLabels(map.data()->placemarkList()); } for(auto zoomLevel: zoomLevels) { TileIterator iter(world, zoomLevel); qint64 count = 0; qint64 const total = iter.total(); for(auto const &tileId: iter) { ++count; QString const filename = tileFileName(parser, tileId.x(), tileId.y(), zoomLevel); if (!overwriteTiles && QFileInfo(filename).exists()) { continue; } GeoDataDocument* tile = processor.clipTo(zoomLevel, tileId.x(), tileId.y()); if (!tile->isEmpty()) { NodeReducer nodeReducer(tile, TileId(0, zoomLevel, tileId.x(), tileId.y())); if (!writeTile(tile, filename)) { return 4; } TileDirectory::printProgress(count / double(total)); std::cout << " Tile " << count << "/" << total << " (" << tile->name().toStdString() << ") done."; double const reduction = nodeReducer.removedNodes() / qMax(1.0, double(nodeReducer.remainingNodes() + nodeReducer.removedNodes())); std::cout << " Node reduction: " << qRound(reduction * 100.0) << "%"; } else { TileDirectory::printProgress(count / double(total)); std::cout << " Skipping empty tile " << count << "/" << total << " (" << tile->name().toStdString() << ")."; } std::cout << std::string(20, ' ') << '\r'; std::cout.flush(); delete tile; } } } else { QString const region = QFileInfo(inputFileName).fileName(); QString const regionDir = QString("%1/%2").arg(cacheDirectory).arg(QFileInfo(inputFileName).baseName()); TileDirectory mapTiles(TileDirectory::OpenStreetMap, regionDir, manager, extension, maxZoomLevel); mapTiles.setInputFile(inputFileName); mapTiles.createTiles(); auto const boundingBox = mapTiles.boundingBox(); TileDirectory loader(TileDirectory::Landmass, cacheDirectory, manager, extension, maxZoomLevel); loader.setBoundingBox(boundingBox); loader.createTiles(); typedef QMap > Tiles; Tiles tiles; qint64 total = 0; QSet boundaryTiles; for(auto zoomLevel: zoomLevels) { TileIterator iter(mapTiles.boundingBox(), zoomLevel); total += iter.total(); for(auto const &tileId: iter) { auto const tile = TileId(0, zoomLevel, tileId.x(), tileId.y()); int const innerNodes = mapTiles.innerNodes(tile); if (innerNodes > 0) { auto const mapTile = mapTiles.tileFor(zoomLevel, tileId.x(), tileId.y()); auto const name = QString("%1/%2/%3").arg(mapTile.zoomLevel()).arg(mapTile.x()).arg(mapTile.y()); tiles[name] << tile; if (innerNodes < 4) { boundaryTiles << name; } } else { --total; } } } qint64 count = 0; for (auto iter = tiles.begin(), end = tiles.end(); iter != end; ++iter) { for(auto const &tileId: iter.value()) { ++count; int const zoomLevel = tileId.zoomLevel(); QString const filename = tileFileName(parser, tileId.x(), tileId.y(), zoomLevel); if (!overwriteTiles) { if (zoomLevel > 13 && mbtileWriter && mbtileWriter->hasTile(tileId.x(), tileId.y(), zoomLevel)) { continue; } else if (QFileInfo(filename).exists()) { continue; } } - typedef QSharedPointer GeoDocPtr; + using GeoDocPtr = QSharedPointer; GeoDocPtr tile2 = GeoDocPtr(loader.clip(zoomLevel, tileId.x(), tileId.y())); if (!tile2->isEmpty()) { GeoDocPtr tile1 = GeoDocPtr(mapTiles.clip(zoomLevel, tileId.x(), tileId.y())); TagsFilter::removeAnnotationTags(tile1.data()); int originalWays = 0; int mergedWays = 0; if (zoomLevel < 17) { WayConcatenator concatenator(tile1.data()); originalWays = concatenator.originalWays(); mergedWays = concatenator.mergedWays(); } NodeReducer nodeReducer(tile1.data(), tileId); if (!tile1->isEmpty() && !tile2->isEmpty()) { GeoDocPtr combined = GeoDocPtr(mergeDocuments(tile1.data(), tile2.data())); if (writeBoundaries && boundaryTiles.contains(iter.key())) { writeBoundaryTile(tile1.data(), region, parser, tileId.x(), tileId.y(), zoomLevel); if (mergeTiles) { combined = mergeBoundaryTiles(tile2, manager, parser, tileId.x(), tileId.y(), zoomLevel); } } if (zoomLevel > 13 && mbtileWriter) { QBuffer buffer; buffer.open(QBuffer::ReadWrite); if (GeoDataDocumentWriter::write(&buffer, *combined, extension)) { buffer.seek(0); mbtileWriter->addTile(&buffer, tileId.x(), tileId.y(), zoomLevel); } else { qWarning() << "Could not write the tile " << combined->name(); } } else { if (!writeTile(combined.data(), filename)) { return 4; } } TileDirectory::printProgress(count / double(total)); std::cout << " Tile " << count << "/" << total << " ("; std::cout << combined->name().toStdString() << ")."; double const reduction = nodeReducer.removedNodes() / qMax(1.0, double(nodeReducer.remainingNodes() + nodeReducer.removedNodes())); std::cout << " Node reduction: " << qRound(reduction * 100.0) << "%"; if (originalWays > 0) { std::cout << " , " << originalWays << " ways merged to " << mergedWays; } } else { TileDirectory::printProgress(count / double(total)); std::cout << " Skipping empty tile " << count << "/" << total << " (" << tile1->name().toStdString() << ")."; } } else { TileDirectory::printProgress(count / double(total)); std::cout << " Skipping sea tile " << count << "/" << total << " (" << tile2->name().toStdString() << ")."; } std::cout << std::string(20, ' ') << '\r'; std::cout.flush(); } } TileDirectory::printProgress(1.0); std::cout << " Vector OSM tiles complete." << std::string(30, ' ') << std::endl; } return 0; }