QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
Loading...
Searching...
No Matches
qgsmapoverviewcanvas.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmapoverviewcanvas.cpp
3 Map canvas subclassed for overview
4 -------------------
5 begin : 09/14/2005
6 copyright : (C) 2005 by Martin Dobias
7 email : won.der at centrum.sk
8 ***************************************************************************/
9
10/***************************************************************************
11 * *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
19#include "qgsmapcanvas.h"
20#include "qgsmaplayer.h"
21#include "qgsproject.h"
24#include "qgsmaptopixel.h"
26
27#include <QPainter>
28#include <QPainterPath>
29#include <QPaintEvent>
30#include <QResizeEvent>
31#include <QMouseEvent>
32#include "qgslogger.h"
33#include <limits>
34
35
37 : QWidget( parent )
38 , mMapCanvas( mapCanvas )
39
40{
41 setAutoFillBackground( true );
42 setObjectName( QStringLiteral( "theOverviewCanvas" ) );
43 mPanningWidget = new QgsPanningWidget( this );
44
47
52
54}
55
56void QgsMapOverviewCanvas::resizeEvent( QResizeEvent *e )
57{
58 mPixmap = QPixmap();
59
60 mSettings.setOutputSize( e->size() );
61
63
64 refresh();
65
66 QWidget::resizeEvent( e );
67}
68
70{
71 refresh();
72 QWidget::showEvent( e );
73}
74
75void QgsMapOverviewCanvas::paintEvent( QPaintEvent *pe )
76{
77 QPainter paint( this );
78 if ( !mPixmap.isNull() )
79 {
80 paint.drawPixmap( pe->rect().topLeft(), mPixmap, pe->rect() );
81 }
82 else
83 {
84 paint.fillRect( pe->rect(), QBrush( mSettings.backgroundColor() ) );
85 }
86}
87
88
90{
91 if ( !mMapCanvas ) return;
92
93 const QgsRectangle &extent = mMapCanvas->extent();
94
95 // show only when valid extent is set
96 if ( extent.isEmpty() || mSettings.visibleExtent().isEmpty() )
97 {
98 mPanningWidget->hide();
99 return;
100 }
101
102 const QPolygonF &vPoly = mMapCanvas->mapSettings().visiblePolygon();
103 const QgsMapToPixel &cXf = mSettings.mapToPixel();
104 QVector< QPoint > pts;
105 pts.push_back( cXf.transform( QgsPointXY( vPoly[0] ) ).toQPointF().toPoint() );
106 pts.push_back( cXf.transform( QgsPointXY( vPoly[1] ) ).toQPointF().toPoint() );
107 pts.push_back( cXf.transform( QgsPointXY( vPoly[2] ) ).toQPointF().toPoint() );
108 pts.push_back( cXf.transform( QgsPointXY( vPoly[3] ) ).toQPointF().toPoint() );
109 mPanningWidget->setPolygon( QPolygon( pts ) );
110 mPanningWidget->show(); // show if hidden
111}
112
113
115{
116// if (mPanningWidget->isHidden())
117// return;
118
119 // set offset in panning widget if inside it
120 // for better experience with panning :)
121 if ( mPanningWidget->geometry().contains( e->pos() ) )
122 {
123 mPanningCursorOffset = e->pos() - mPanningWidget->pos();
124 }
125 else
126 {
127 // use center of the panning widget if outside
128 const QSize s = mPanningWidget->size();
129 mPanningCursorOffset = QPoint( s.width() / 2, s.height() / 2 );
130 }
131 updatePanningWidget( e->pos() );
132}
133
134
136{
137// if (mPanningWidget->isHidden())
138// return;
139
140 if ( e->button() == Qt::LeftButton )
141 {
142 // set new extent
143 const QgsMapToPixel &cXf = mSettings.mapToPixel();
144 const QRect rect = mPanningWidget->geometry();
145
146 const QgsPointXY center = cXf.toMapCoordinates( rect.center() );
147 mMapCanvas->setCenter( center );
149 }
150}
151
152
154{
155 QgsSettings settings;
156 bool reverseZoom = settings.value( QStringLiteral( "qgis/reverse_wheel_zoom" ), false ).toBool();
157 bool zoomIn = reverseZoom ? e->angleDelta().y() < 0 : e->angleDelta().y() > 0;
158 double zoomFactor = zoomIn ? 1. / mMapCanvas->zoomInFactor() : mMapCanvas->zoomOutFactor();
159
160 // "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
161 zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * std::fabs( e->angleDelta().y() );
162
163 if ( e->modifiers() & Qt::ControlModifier )
164 {
165 //holding ctrl while wheel zooming results in a finer zoom
166 zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
167 }
168
169 const double signedWheelFactor = zoomIn ? 1 / zoomFactor : zoomFactor;
170
171 const QgsMapToPixel &cXf = mSettings.mapToPixel();
172 const QgsPointXY center = cXf.toMapCoordinates( e->position().x(), e->position().y() );
173 updatePanningWidget( QPoint( e->position().x(), e->position().y() ) );
174 mMapCanvas->zoomByFactor( signedWheelFactor, &center );
175}
176
178{
179 // move with panning widget if tracking cursor
180 if ( ( e->buttons() & Qt::LeftButton ) == Qt::LeftButton )
181 {
182 updatePanningWidget( e->pos() );
183 }
184}
185
186
188{
189// if (mPanningWidget->isHidden())
190// return;
191 mPanningWidget->move( pos.x() - mPanningCursorOffset.x(), pos.y() - mPanningCursorOffset.y() );
192}
193
195{
196 if ( !isVisible() )
197 return;
198
200
202 {
203 mPixmap = QPixmap();
204 update();
205 return; // makes no sense to render anything
206 }
207
208 if ( mJob )
209 {
210 QgsDebugMsgLevel( QStringLiteral( "oveview - canceling old" ), 2 );
211 mJob->cancel();
212 QgsDebugMsgLevel( QStringLiteral( "oveview - deleting old" ), 2 );
213 delete mJob; // get rid of previous job (if any)
214 }
215
216 QgsDebugMsgLevel( QStringLiteral( "oveview - starting new" ), 2 );
217
218 // TODO: setup overview mode
221 mJob->start();
222
224
225 // schedule repaint
226 update();
227
228 // update panning widget
230}
231
233{
234 QgsDebugMsgLevel( QStringLiteral( "overview - finished" ), 2 );
235 mPixmap = QPixmap::fromImage( mJob->renderedImage() );
236
237 delete mJob;
238 mJob = nullptr;
239
240 // schedule repaint
241 update();
242}
243
245{
246 if ( !deferred )
247 refresh();
248}
249
250
252{
254
255 // set erase color
256 QPalette palette;
257 palette.setColor( backgroundRole(), color );
258 setPalette( palette );
259}
260
261void QgsMapOverviewCanvas::setLayers( const QList<QgsMapLayer *> &layers )
262{
263 const auto oldLayers = mSettings.layers();
264 for ( QgsMapLayer *ml : oldLayers )
265 {
267 }
268
270
271 const auto newLayers = mSettings.layers();
272 for ( QgsMapLayer *ml : newLayers )
273 {
275 }
276
277 refresh();
278}
279
281{
282 QgsRectangle rect;
283 if ( !QgsProject::instance()->viewSettings()->presetFullExtent().isNull() )
284 {
288 try
289 {
290 rect = ct.transformBoundingBox( extent );
291 }
292 catch ( QgsCsException & )
293 {
294 }
295 }
296
297 if ( rect.isNull() )
298 {
300 rect = mSettings.fullExtent();
301 else
302 rect = mMapCanvas->projectExtent();
303 }
304
305 // expand a bit to keep features on margin
306 rect.scale( 1.1 );
307
308 mSettings.setExtent( rect );
310}
311
316
321
322QList<QgsMapLayer *> QgsMapOverviewCanvas::layers() const
323{
324 return mSettings.layers();
325}
326
327
329
330QgsPanningWidget::QgsPanningWidget( QWidget *parent )
331 : QWidget( parent )
332{
333 setObjectName( QStringLiteral( "panningWidget" ) );
334 setMinimumSize( 5, 5 );
335 setAttribute( Qt::WA_NoSystemBackground );
336}
337
338void QgsPanningWidget::setPolygon( const QPolygon &p )
339{
340 if ( p == mPoly ) return;
341 mPoly = p;
342
343 //ensure polygon is closed
344 if ( mPoly.at( 0 ) != mPoly.at( mPoly.length() - 1 ) )
345 mPoly.append( mPoly.at( 0 ) );
346
347 const QRect rect = p.boundingRect() + QMargins( 1, 1, 1, 1 );
348 setGeometry( rect );
349 update();
350}
351
352void QgsPanningWidget::paintEvent( QPaintEvent *pe )
353{
354 Q_UNUSED( pe )
355
356 QPainter p;
357
358 p.begin( this );
359 const QPolygonF t = mPoly.translated( -mPoly.boundingRect().left() + 1, -mPoly.boundingRect().top() + 1 );
360
361 // drawPolygon causes issues on windows - corners of path may be missing resulting in triangles being drawn
362 // instead of rectangles! (Same cause as #13343)
363 QPainterPath path;
364 path.addPolygon( t );
365
366 QPen pen;
367 pen.setJoinStyle( Qt::MiterJoin );
368 pen.setColor( Qt::white );
369 pen.setWidth( 3 );
370 p.setPen( pen );
371 p.drawPath( path );
372 pen.setColor( Qt::red );
373 pen.setWidth( 1 );
374 p.setPen( pen );
375 p.drawPath( path );
376
377 p.end();
378}
379
380
381
@ DrawLabeling
Enable drawing of labels on top of the map.
Class for doing transforms between two map coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
Custom exception class for Coordinate Reference System related exceptions.
Map canvas is a class for displaying all GIS data types on a canvas.
void extentsChanged()
Emitted when the extents of the map change.
void zoomByFactor(double scaleFactor, const QgsPointXY *center=nullptr, bool ignoreScaleLock=false)
Zoom with the factor supplied.
void canvasColorChanged()
Emitted when canvas background color changes.
double zoomInFactor() const
Returns the zoom in factor.
double zoomOutFactor() const
Returns the zoom in factor.
QgsRectangle projectExtent() const
Returns the associated project's full extent, in the canvas' CRS.
void setCenter(const QgsPointXY &center)
Set the center of the map canvas, in geographical coordinates.
void destinationCrsChanged()
Emitted when map CRS has changed.
void transformContextChanged()
Emitted when the canvas transform context is changed.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
void refresh()
Repaints the canvas map.
Base class for all map layer types.
Definition qgsmaplayer.h:74
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
QPoint mPanningCursorOffset
position of cursor inside panning widget
void wheelEvent(QWheelEvent *e) override
Overridden mouse release event.
void resizeEvent(QResizeEvent *e) override
Overridden resize event.
void setLayers(const QList< QgsMapLayer * > &layers)
updates layer set for overview
void drawExtentRect()
used for overview canvas to reflect changed extent in main map canvas
void mouseReleaseEvent(QMouseEvent *e) override
Overridden mouse release event.
void mouseMoveEvent(QMouseEvent *e) override
Overridden mouse move event.
void transformContextChanged()
Called when the canvas transform context is changed.
void refresh()
renders overview and updates panning widget
void mousePressEvent(QMouseEvent *e) override
Overridden mouse press event.
void layerRepaintRequested(bool deferred=false)
Triggered when a layer in the overview requests a repaint.
void paintEvent(QPaintEvent *pe) override
Overridden paint event.
void setBackgroundColor(const QColor &color)
changes background color
QgsMapOverviewCanvas(QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr)
QgsMapRendererQImageJob * mJob
for rendering overview
void destinationCrsChanged()
Should be called when the canvas destination CRS is changed.
QPixmap mPixmap
pixmap where the map is stored
QgsPanningWidget * mPanningWidget
widget for panning map in overview
void showEvent(QShowEvent *e) override
Overridden show event.
void updatePanningWidget(QPoint pos)
called when panning to reflect mouse movement
QgsMapSettings mSettings
map settings used for rendering of the overview map
QList< QgsMapLayer * > layers() const
Returns list of layers visible in the overview.
QgsMapCanvas * mMapCanvas
main map canvas - used to get/set extent
void finished()
emitted when asynchronous rendering is finished (or canceled).
void start()
Start the rendering job and immediately return.
virtual void cancel()=0
Stop the rendering job - does not return until the job has terminated.
virtual QImage renderedImage()=0
Gets a preview/resulting image.
Job implementation that renders everything sequentially in one thread.
QList< QgsMapLayer * > layers(bool expandGroupLayers=false) const
Returns the list of layers which will be rendered in the map.
QPolygonF visiblePolygon() const
Returns the visible area as a polygon (may be rotated)
void setLayers(const QList< QgsMapLayer * > &layers)
Sets the list of layers to render in the map.
QColor backgroundColor() const
Returns the background color of the map.
const QgsMapToPixel & mapToPixel() const
void setExtent(const QgsRectangle &rect, bool magnified=true)
Sets the coordinates of the rectangle which should be rendered.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
QgsRectangle fullExtent() const
returns current extent of layer set
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the coordinate transform context, which stores various information regarding which datum transfo...
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
void setOutputSize(QSize size)
Sets the size of the resulting map image, in pixels.
void setBackgroundColor(const QColor &color)
Sets the background color of the map.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
void setFlag(Qgis::MapSettingsFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
Sets the destination crs (coordinate reference system) for the map render.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
Perform transforms between map coordinates and device coordinates.
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
A class to represent a 2D point.
Definition qgspointxy.h:59
void presetFullExtentChanged()
Emitted whenever the presetFullExtent() is changed.
QgsReferencedRectangle fullExtent() const
Returns the full extent of the project, which represents the maximal limits of the project.
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsCoordinateTransformContext transformContext
Definition qgsproject.h:113
const QgsProjectViewSettings * viewSettings() const
Returns the project's view settings, which contains settings and properties relating to how a QgsProj...
A rectangle specified with double values.
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
bool isNull() const
Test if the rectangle is null (holding no spatial information).
bool isEmpty() const
Returns true if the rectangle has no area.
QgsCoordinateReferenceSystem crs() const
Returns the associated coordinate reference system, or an invalid CRS if no reference system is set.
A QgsRectangle with associated coordinate reference system.
This class is a composition of two QSettings instances:
Definition qgssettings.h:63
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39