QGIS API Documentation  2.99.0-Master (19b062c)
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 
26 #include <QPainter>
27 #include <QPaintEvent>
28 #include <QResizeEvent>
29 #include <QMouseEvent>
30 #include "qgslogger.h"
31 #include <limits>
32 
33 
35  : QWidget( parent )
36  , mMapCanvas( mapCanvas )
37 
38 {
39  setAutoFillBackground( true );
40  setObjectName( QStringLiteral( "theOverviewCanvas" ) );
41  mPanningWidget = new QgsPanningWidget( this );
42 
44 
47 }
48 
49 void QgsMapOverviewCanvas::resizeEvent( QResizeEvent *e )
50 {
51  mPixmap = QPixmap();
52 
53  mSettings.setOutputSize( e->size() );
54 
56 
57  refresh();
58 
59  QWidget::resizeEvent( e );
60 }
61 
62 void QgsMapOverviewCanvas::showEvent( QShowEvent *e )
63 {
64  refresh();
65  QWidget::showEvent( e );
66 }
67 
68 void QgsMapOverviewCanvas::paintEvent( QPaintEvent *pe )
69 {
70  if ( !mPixmap.isNull() )
71  {
72  QPainter paint( this );
73  paint.drawPixmap( pe->rect().topLeft(), mPixmap, pe->rect() );
74  }
75 }
76 
77 
79 {
80  if ( !mMapCanvas ) return;
81 
82  const QgsRectangle &extent = mMapCanvas->extent();
83 
84  // show only when valid extent is set
85  if ( extent.isEmpty() || mSettings.visibleExtent().isEmpty() )
86  {
87  mPanningWidget->hide();
88  return;
89  }
90 
91  const QPolygonF &vPoly = mMapCanvas->mapSettings().visiblePolygon();
92  const QgsMapToPixel &cXf = mSettings.mapToPixel();
93  QVector< QPoint > pts;
94  pts.push_back( cXf.transform( QgsPointXY( vPoly[0] ) ).toQPointF().toPoint() );
95  pts.push_back( cXf.transform( QgsPointXY( vPoly[1] ) ).toQPointF().toPoint() );
96  pts.push_back( cXf.transform( QgsPointXY( vPoly[2] ) ).toQPointF().toPoint() );
97  pts.push_back( cXf.transform( QgsPointXY( vPoly[3] ) ).toQPointF().toPoint() );
98  mPanningWidget->setPolygon( QPolygon( pts ) );
99  mPanningWidget->show(); // show if hidden
100 }
101 
102 
104 {
105 // if (mPanningWidget->isHidden())
106 // return;
107 
108  // set offset in panning widget if inside it
109  // for better experience with panning :)
110  if ( mPanningWidget->geometry().contains( e->pos() ) )
111  {
112  mPanningCursorOffset = e->pos() - mPanningWidget->pos();
113  }
114  else
115  {
116  // use center of the panning widget if outside
117  QSize s = mPanningWidget->size();
118  mPanningCursorOffset = QPoint( s.width() / 2, s.height() / 2 );
119  }
120  updatePanningWidget( e->pos() );
121 }
122 
123 
125 {
126 // if (mPanningWidget->isHidden())
127 // return;
128 
129  if ( e->button() == Qt::LeftButton )
130  {
131  // set new extent
132  const QgsMapToPixel &cXf = mSettings.mapToPixel();
133  QRect rect = mPanningWidget->geometry();
134 
135  QgsPointXY center = cXf.toMapCoordinates( rect.center() );
136  mMapCanvas->setCenter( center );
137  mMapCanvas->refresh();
138  }
139 }
140 
141 
143 {
144  // move with panning widget if tracking cursor
145  if ( ( e->buttons() & Qt::LeftButton ) == Qt::LeftButton )
146  {
147  updatePanningWidget( e->pos() );
148  }
149 }
150 
151 
153 {
154 // if (mPanningWidget->isHidden())
155 // return;
156  mPanningWidget->move( pos.x() - mPanningCursorOffset.x(), pos.y() - mPanningCursorOffset.y() );
157 }
158 
160 {
161  if ( !isVisible() )
162  return;
163 
165 
166  if ( !mSettings.hasValidSettings() )
167  {
168  mPixmap = QPixmap();
169  update();
170  return; // makes no sense to render anything
171  }
172 
173  if ( mJob )
174  {
175  QgsDebugMsg( "oveview - canceling old" );
176  mJob->cancel();
177  QgsDebugMsg( "oveview - deleting old" );
178  delete mJob; // get rid of previous job (if any)
179  }
180 
181  QgsDebugMsg( "oveview - starting new" );
182 
183  // TODO: setup overview mode
186  mJob->start();
187 
189 
190  // schedule repaint
191  update();
192 
193  // update panning widget
194  drawExtentRect();
195 }
196 
198 {
199  QgsDebugMsg( "overview - finished" );
200  mPixmap = QPixmap::fromImage( mJob->renderedImage() );
201 
202  delete mJob;
203  mJob = nullptr;
204 
205  // schedule repaint
206  update();
207 }
208 
210 {
211  if ( !deferred )
212  refresh();
213 }
214 
215 
216 void QgsMapOverviewCanvas::setBackgroundColor( const QColor &color )
217 {
218  mSettings.setBackgroundColor( color );
219 
220  // set erase color
221  QPalette palette;
222  palette.setColor( backgroundRole(), color );
223  setPalette( palette );
224 }
225 
226 void QgsMapOverviewCanvas::setLayers( const QList<QgsMapLayer *> &layers )
227 {
228  Q_FOREACH ( QgsMapLayer *ml, mSettings.layers() )
229  {
231  }
232 
233  mSettings.setLayers( layers );
234 
235  Q_FOREACH ( QgsMapLayer *ml, mSettings.layers() )
236  {
238  }
239 
241 
242  refresh();
243 }
244 
246 {
247  QgsRectangle rect;
248  if ( mSettings.hasValidSettings() )
249  rect = mSettings.fullExtent();
250  else
251  rect = mMapCanvas->fullExtent();
252 
253  // expand a bit to keep features on margin
254  rect.scale( 1.1 );
255 
256  mSettings.setExtent( rect );
257  drawExtentRect();
258 }
259 
261 {
263 }
264 
265 QList<QgsMapLayer *> QgsMapOverviewCanvas::layers() const
266 {
267  return mSettings.layers();
268 }
269 
270 
272 
273 QgsPanningWidget::QgsPanningWidget( QWidget *parent )
274  : QWidget( parent )
275 {
276  setObjectName( QStringLiteral( "panningWidget" ) );
277  setMinimumSize( 5, 5 );
278  setAttribute( Qt::WA_NoSystemBackground );
279 }
280 
281 void QgsPanningWidget::setPolygon( const QPolygon &p )
282 {
283  if ( p == mPoly ) return;
284  mPoly = p;
285 
286  //ensure polygon is closed
287  if ( mPoly.at( 0 ) != mPoly.at( mPoly.length() - 1 ) )
288  mPoly.append( mPoly.at( 0 ) );
289 
290  setGeometry( p.boundingRect() );
291  update();
292 }
293 
294 void QgsPanningWidget::paintEvent( QPaintEvent *pe )
295 {
296  Q_UNUSED( pe );
297 
298  QPainter p;
299  p.begin( this );
300  p.setPen( Qt::red );
301  QPolygonF t = mPoly.translated( -mPoly.boundingRect().left(), -mPoly.boundingRect().top() );
302 
303  // drawPolygon causes issues on windows - corners of path may be missing resulting in triangles being drawn
304  // instead of rectangles! (Same cause as #13343)
305  QPainterPath path;
306  path.addPolygon( t );
307  p.drawPath( path );
308 
309  p.end();
310 }
311 
312 
313 
QPoint mPanningCursorOffset
position of cursor inside panning widget
void layerRepaintRequested(bool deferred=false)
Triggered when a layer in the overview requests a repaint.
void finished()
emitted when asynchronous rendering is finished (or canceled).
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
A rectangle specified with double values.
Definition: qgsrectangle.h:39
Base class for all map layer types.
Definition: qgsmaplayer.h:56
void setExtent(const QgsRectangle &rect, bool magnified=true)
Set coordinates of the rectangle which should be rendered.
void setCenter(const QgsPointXY &center)
Set the center of the map canvas, in geographical coordinates.
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
A class to represent a 2D point.
Definition: qgspointxy.h:43
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
QgsMapCanvas * mMapCanvas
main map canvas - used to get/set extent
QgsMapRendererQImageJob * mJob
for rendering overview
QColor backgroundColor() const
Get the background color of the map.
void updatePanningWidget(QPoint pos)
called when panning to reflect mouse movement
void refresh()
Repaints the canvas map.
QList< QgsMapLayer * > layers() const
Get list of layers for map rendering The layers are stored in the reverse order of how they are rende...
void setBackgroundColor(const QColor &color)
changes background color
virtual QImage renderedImage()=0
Get a preview/resulting image.
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
Enable drawing of labels on top of the map.
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.cpp:40
void setOutputSize(QSize size)
Set the size of the resulting map image.
void showEvent(QShowEvent *e) override
Overridden show event.
QgsPanningWidget * mPanningWidget
widget for panning map in overview
bool isEmpty() const
Returns true if the rectangle is empty.
void setLayers(const QList< QgsMapLayer *> &layers)
updates layer set for overview
QgsMapSettings mSettings
map settings used for rendering of the overview map
QList< QgsMapLayer * > layers() const
Returns list of layers visible in the overview.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
void mouseMoveEvent(QMouseEvent *e) override
Overridden mouse move event.
void destinationCrsChanged()
Emitted when map CRS has changed.
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
QgsMapOverviewCanvas(QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr)
void refresh()
renders overview and updates panning widget
const QgsMapToPixel & mapToPixel() const
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
virtual void start()=0
Start the rendering job and immediately return.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
Job implementation that renders everything sequentially in one thread.
void setBackgroundColor(const QColor &color)
Set the background color of the map.
void paintEvent(QPaintEvent *pe) override
Overridden paint event.
QPixmap mPixmap
pixmap where the map is stored
QgsRectangle fullExtent() const
returns current extent of layer set
QgsRectangle fullExtent() const
Returns the combined extent for all layers on the map canvas.
void setLayers(const QList< QgsMapLayer *> &layers)
Set list of layers for map rendering.
virtual void cancel()=0
Stop the rendering job - does not return until the job has terminated.
void resizeEvent(QResizeEvent *e) override
Overridden resize event.
void destinationCrsChanged()
Should be called when the canvas destination CRS is changed.
QPolygonF visiblePolygon() const
Return the visible area as a polygon (may be rotated)
void mousePressEvent(QMouseEvent *e) override
Overridden mouse press event.
void mouseReleaseEvent(QMouseEvent *e) override
Overridden mouse release event.
void extentsChanged()
Emitted when the extents of the map change.
QgsPointXY toMapCoordinates(int x, int y) const
void drawExtentRect()
used for overview canvas to reflect changed extent in main map canvas