/*************************************************************************** * Copyright (C) gempa GmbH * * All rights reserved. * * Contact: gempa GmbH (seiscomp-dev@gempa.de) * * * * GNU Affero General Public License Usage * * This file may be used under the terms of the GNU Affero * * Public License version 3.0 as published by the Free Software Foundation * * and appearing in the file LICENSE included in the packaging of this * * file. Please review the following information to ensure the GNU Affero * * Public License version 3.0 requirements will be met: * * https://www.gnu.org/licenses/agpl-3.0.html. * * * * Other Usage * * Alternatively, this file may be used in accordance with the terms and * * conditions contained in a signed written agreement between you and * * gempa GmbH. * ***************************************************************************/ #ifndef SEISCOMP_GUI_MAP_CANVAS_H #define SEISCOMP_GUI_MAP_CANVAS_H #ifndef Q_MOC_RUN #include #include #include #include #include #include #include #include #include #include #include #endif #include #include #include class QMouseEvent; class QMenu; namespace Seiscomp { namespace Gui { namespace Map { class Layer; DEFINE_SMARTPOINTER(TextureCache); // For backward compatibility typedef SymbolLayer SymbolCollection; class SC_GUI_API Canvas : public QObject { Q_OBJECT public: Canvas(const MapsDesc &); Canvas(ImageTree *mapTree); ~Canvas(); public: void setFont(QFont f); QFont font() const { return _font; } void setBackgroundColor(QColor c); bool setProjectionByName(const char *name); const std::string &projectionName() const { return _projectionName; } void setSize(int w, int h); QSize size() const { return _buffer.size(); } int width() const { return _buffer.width(); } int height() const { return _buffer.height(); } /** * @brief Sets the margin of the legend area with respect to the * canvas border. The default value is 10 pixels. This methods * was added with API 11. * @param margin The margin in pixels. */ void setLegendMargin(int margin); /** * @brief Returns the margin of the legend area with respect to the * canvas border. This methods was added with API 11. * @return The margin in pixels */ int legendMargin() const { return _margin; } void setGrayScale(bool); bool isGrayScale() const; /** * @brief Sets bilinear filtering for map tile interpolation. This is * only used if not in preview mode. * @param enable Boolean flag */ void setBilinearFilter(bool enable); /** * @brief Enables the preview mode. The preview mode is meant to be * used for fast rendering the map, e.g. with antialiasing * switched of. This is mainly used while dragging the map. * @param enable Boolean flag */ void setPreviewMode(bool enable); /** * @brief Returns whether the canvas rendering is currently in preview * mode or not. * @return A boolean flag */ bool previewMode() const; void setDrawGrid(bool); bool isDrawGridEnabled() const; void setDrawLayers(bool); bool isDrawLayersEnabled() const; void setDrawCities(bool); bool isDrawCitiesEnabled() const; bool isDrawLegendsEnabled() const; void setImageFilter(bool); bool isImageFilterEnabled() const; bool displayRect(const QRectF& rect); void setMapCenter(QPointF c); const QPointF& mapCenter() const; bool setZoomLevel(float); float zoomLevel() const; float pixelPerDegree() const; void setView(QPoint c, float zoom); void setView(QPointF c, float zoom); /** * @brief Sets the minimum pixel distance of two adjacent vertices * to be rendered as a line when rendering GeoFeatures and polylines. * Or in other words, if the pixel distance of two adjacent vertices is * less than the given distance, both vertices collapse into a single * vertex. The greater the distance the less details the rendered shape * will have. * @param pixel The distance in pixels */ void setPolygonRoughness(uint pixel); uint polygonRoughness() const; /** * @brief Sets the polygon clip hint. * * The hint might or might not be interpreted by projections. If the * clipHint is DoClip then polygons are clipped against the viewport * before rendering them. This will reduce the number of vertices * significantly but also increases processing time. The default * is DoClip. * @param hint The clipping hint */ void setPolygonClipHint(ClipHint hint); ClipHint polygonClipHint() const; Map::Projection *projection() const { return _projection; } bool isVisible(double lon, double lat) const; void setSelectedCity(const Math::Geo::CityD*); //! Draws a geometric line (great circle) given in geographical coordinates (lon, lat) //! Returns the distance in degree of the line double drawLine(QPainter &painter, const QPointF &start, const QPointF &end) const; //! Draws a polyline in geographical coordinates (lon, lat). //! Returns number of line segments drawn. //! Does not check for clipping size_t drawPolyline(QPainter &painter, size_t n, const Geo::GeoCoordinate *line, bool isClosedPolygon, bool interpolate = false, int roughness = -1) const; //! Does not check for clipping size_t drawPolygon(QPainter &painter, size_t n, const Geo::GeoCoordinate *line, bool isClosedPolygon = true, int roughness = -1, ClipHint clipHint = DoClip) const; //! Draws a GeoFeature as either polyline or filled polygon and //! checks for clipping size_t drawFeature(QPainter &painter, const Geo::GeoFeature *feature, bool filled = false, int roughness = -1, ClipHint clipHint = DoClip) const; /** * @brief Draws an image onto the current map buffer. If this function * is called *after* @drawImageLayer then it does not have an * effect because the map buffer has been rendered already onto * the painter device. * @param geoReference The geo reference of the image. * @param image The image to be rendered. * @param compositionMode The composition mode which will be used to * combine the current base layer (tiles) with * the image. * @param filterMode The filter mode used to render the image. */ void drawImage(const QRectF &geoReference, const QImage &image, CompositionMode compositionMode = CompositionMode_Default, FilterMode filterMode = FilterMode_Auto); void draw(QPainter &p); void centerMap(const QPoint ¢erPnt); void translate(const QPoint &delta); void translate(const QPointF &delta); void drawImageLayer(QPainter &painter); void drawVectorLayer(QPainter &painter); void drawLayers(QPainter &painter); void updateBuffer(); void setBuffer(QImage buffer) { _buffer = buffer; } QImage &buffer() { return _buffer; } //! Returns the number of layers int layerCount() const { return _layers.count(); } //! Returns the i-th layer if the index is valid Layer* layer(int i) const { if ( i < 0 || i >= _layers.count() ) return nullptr; return _layers[i]; } //! Canvas does take ownership of layer if the layer does not //! have a parent at the time of appending or prepending. bool prependLayer(Layer*); bool addLayer(Layer*); bool insertLayerBefore(const Layer*, Layer*); void removeLayer(Layer*); void lower(Layer*); void raise(Layer*); Layer *hoverLayer() const; bool filterContextMenuEvent(QContextMenuEvent*, QWidget*); bool filterKeyPressEvent(QKeyEvent *event); bool filterKeyReleaseEvent(QKeyEvent *event); bool filterMouseMoveEvent(QMouseEvent*); bool filterMousePressEvent(QMouseEvent*); bool filterMouseReleaseEvent(QMouseEvent*); bool filterMouseDoubleClickEvent(QMouseEvent*); QMenu* menu(QMenu*) const; //! Returns whether the rendering is complete or if there are //! still some updates in the pipeline that updated later. If this //! function return false, the signal renderingCompleted() is emitted //! once it is done. //! This function was introduced in API 1.1. bool renderingComplete() const; public: GridLayer *gridLayer(); const GridLayer *gridLayer() const; CitiesLayer *citiesLayer(); const CitiesLayer *citiesLayer() const; GeoFeatureLayer *geoFeatureLayer(); const GeoFeatureLayer *geoFeatureLayer() const; SymbolLayer *symbolCollection(); const SymbolLayer *symbolCollection() const; public slots: //! Reloads all tiles and empties the texture cache //! This slot was introduced in API 1.1. void reload(); //! This slot was added in API 11 void setDrawLegends(bool); //! This slot was added in API 11 void showLegends(); //! This slot was added in API 11 void hideLegends(); /** * @brief Enables/disables legend stacking. * * If legend stacking is enabled then two toggle buttons will be * rendered in the legends title bar to swap the visible legend. If * stacking is disabled then all legends of a particular edge will * be rendered next to each other. This slot was added in API 11. */ void setLegendStacking(bool); void bringToFront(Seiscomp::Gui::Map::Legend*); void setLegendEnabled(Seiscomp::Gui::Map::Legend*, bool); /** * @brief This handler is called when a new legend is * added to a layer. * This slot was introduced with API XX * @param legend The legend */ void onLegendAdded(Legend *legend); /** * @brief This handler is called when a legend is removed * from a layer. * This slot was introduced with API XX * @param legend */ void onLegendRemoved(Legend *legend); signals: //! This signal is emitted if draw() caused asynchronous data requests //! and when those requests are finished. //! This signal was introduced with API 1.1. void renderingCompleted(); void bufferUpdated(); void projectionChanged(Seiscomp::Gui::Map::Projection*); void legendVisibilityChanged(bool); void updateRequested(); void customLayer(QPainter*); private: void init(); void drawCity(QPainter &painter, const Math::Geo::CityD &, QVector< QList > &grid, QFont &font, QFontMetrics &fontMetrics, int rowHeight, bool &lastUnderline, bool &lastBold); void drawLegends(QPainter &painter); void setupLayer(Layer *layer); private slots: void updatedTiles(); void completeTiles(); void updateLayer(const Layer::UpdateHints&); private: struct LegendItem { LegendItem() : legend(0), dirty(true) {} LegendItem(Legend *legend) : legend(legend), dirty(true) {} Legend *legend; bool dirty; }; typedef QVector Legends; struct LegendArea : public Legends { LegendArea() : currentIndex(-1) {} int find(Legend *legend) const { for ( int i = 0; i < count(); ++i ) { if ( at(i).legend == legend ) return i; } return -1; } bool hasIndex(int index) { return ( index >= 0 && index < count() ); } bool mousePressEvent(QMouseEvent *e); bool mouseReleaseEvent(QMouseEvent *e); int findNext(bool forward = true) const; QRect header; QRect decorationRects[2]; int currentIndex; }; typedef QHash LegendAreas; typedef QList Layers; typedef QList CustomLayers; private: QFont _font; Projection* _projection; ImageTreePtr _maptree; std::string _projectionName; QImage _buffer; QColor _backgroundColor{Qt::lightGray}; uint _polygonRoughness; double _maxZoom; QPointF _center; float _zoomLevel{1.0f}; bool _grayScale{false}; bool _filterMap; bool _dirtyRasterLayer{true}; bool _dirtyVectorLayers{true}; bool _previewMode{false}; bool _stackLegends{true}; Layers _layers; Layer *_hoverLayer{nullptr}; CustomLayers _customLayers; CitiesLayer _citiesLayer; GridLayer _gridLayer; GeoFeatureLayer _geoFeatureLayer; SymbolLayer _symbolLayer; LegendAreas _legendAreas; int _margin{10}; bool _isDrawLegendsEnabled{true}; Util::StopWatch _tileUpdateTimer; }; inline bool Canvas::previewMode() const { return _previewMode; } inline Layer *Canvas::hoverLayer() const { return _hoverLayer; } inline GridLayer *Canvas::gridLayer() { return &_gridLayer; } inline const GridLayer *Canvas::gridLayer() const { return &_gridLayer; } inline CitiesLayer *Canvas::citiesLayer() { return &_citiesLayer; } inline const CitiesLayer *Canvas::citiesLayer() const { return &_citiesLayer; } inline GeoFeatureLayer *Canvas::geoFeatureLayer() { return &_geoFeatureLayer; } inline const GeoFeatureLayer *Canvas::geoFeatureLayer() const { return &_geoFeatureLayer; } inline SymbolLayer *Canvas::symbolCollection() { return &_symbolLayer; } inline const SymbolLayer *Canvas::symbolCollection() const { return &_symbolLayer; } inline uint Canvas::polygonRoughness() const { return _polygonRoughness; } inline void Canvas::setPolygonRoughness(uint pixel) { _polygonRoughness = pixel; } } } } #endif