You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
496 lines
14 KiB
C
496 lines
14 KiB
C
2 years ago
|
/***************************************************************************
|
||
|
* 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 <seiscomp/gui/core/maps.h>
|
||
|
#include <seiscomp/gui/map/projection.h>
|
||
|
#include <seiscomp/gui/map/legend.h>
|
||
|
#include <seiscomp/gui/map/imagetree.h>
|
||
|
#include <seiscomp/gui/map/layers/citieslayer.h>
|
||
|
#include <seiscomp/gui/map/layers/gridlayer.h>
|
||
|
#include <seiscomp/gui/map/layers/geofeaturelayer.h>
|
||
|
#include <seiscomp/gui/map/layers/symbollayer.h>
|
||
|
#include <seiscomp/math/coord.h>
|
||
|
#include <seiscomp/geo/feature.h>
|
||
|
#include <seiscomp/utils/timer.h>
|
||
|
#endif
|
||
|
|
||
|
#include <QHash>
|
||
|
#include <QObject>
|
||
|
#include <QPolygon>
|
||
|
|
||
|
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<QRect> > &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<LegendItem> 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<Qt::Alignment, LegendArea> LegendAreas;
|
||
|
|
||
|
typedef QList<Layer*> Layers;
|
||
|
typedef QList<LayerPtr> 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
|