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