QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
45 
49 }
50 
51 void QgsMapOverviewCanvas::resizeEvent( QResizeEvent *e )
52 {
53  mPixmap = QPixmap();
54 
55  mSettings.setOutputSize( e->size() );
56 
58 
59  refresh();
60 
61  QWidget::resizeEvent( e );
62 }
63 
64 void QgsMapOverviewCanvas::showEvent( QShowEvent *e )
65 {
66  refresh();
67  QWidget::showEvent( e );
68 }
69 
70 void QgsMapOverviewCanvas::paintEvent( QPaintEvent *pe )
71 {
72  if ( !mPixmap.isNull() )
73  {
74  QPainter paint( this );
75  paint.drawPixmap( pe->rect().topLeft(), mPixmap, pe->rect() );
76  }
77 }
78 
79 
81 {
82  if ( !mMapCanvas ) return;
83 
84  const QgsRectangle &extent = mMapCanvas->extent();
85 
86  // show only when valid extent is set
87  if ( extent.isEmpty() || mSettings.visibleExtent().isEmpty() )
88  {
89  mPanningWidget->hide();
90  return;
91  }
92 
93  const QPolygonF &vPoly = mMapCanvas->mapSettings().visiblePolygon();
94  const QgsMapToPixel &cXf = mSettings.mapToPixel();
95  QVector< QPoint > pts;
96  pts.push_back( cXf.transform( QgsPointXY( vPoly[0] ) ).toQPointF().toPoint() );
97  pts.push_back( cXf.transform( QgsPointXY( vPoly[1] ) ).toQPointF().toPoint() );
98  pts.push_back( cXf.transform( QgsPointXY( vPoly[2] ) ).toQPointF().toPoint() );
99  pts.push_back( cXf.transform( QgsPointXY( vPoly[3] ) ).toQPointF().toPoint() );
100  mPanningWidget->setPolygon( QPolygon( pts ) );
101  mPanningWidget->show(); // show if hidden
102 }
103 
104 
106 {
107 // if (mPanningWidget->isHidden())
108 // return;
109 
110  // set offset in panning widget if inside it
111  // for better experience with panning :)
112  if ( mPanningWidget->geometry().contains( e->pos() ) )
113  {
114  mPanningCursorOffset = e->pos() - mPanningWidget->pos();
115  }
116  else
117  {
118  // use center of the panning widget if outside
119  QSize s = mPanningWidget->size();
120  mPanningCursorOffset = QPoint( s.width() / 2, s.height() / 2 );
121  }
122  updatePanningWidget( e->pos() );
123 }
124 
125 
127 {
128 // if (mPanningWidget->isHidden())
129 // return;
130 
131  if ( e->button() == Qt::LeftButton )
132  {
133  // set new extent
134  const QgsMapToPixel &cXf = mSettings.mapToPixel();
135  QRect rect = mPanningWidget->geometry();
136 
137  QgsPointXY center = cXf.toMapCoordinates( rect.center() );
138  mMapCanvas->setCenter( center );
139  mMapCanvas->refresh();
140  }
141 }
142 
143 
145 {
146  // move with panning widget if tracking cursor
147  if ( ( e->buttons() & Qt::LeftButton ) == Qt::LeftButton )
148  {
149  updatePanningWidget( e->pos() );
150  }
151 }
152 
153 
155 {
156 // if (mPanningWidget->isHidden())
157 // return;
158  mPanningWidget->move( pos.x() - mPanningCursorOffset.x(), pos.y() - mPanningCursorOffset.y() );
159 }
160 
162 {
163  if ( !isVisible() )
164  return;
165 
167 
168  if ( !mSettings.hasValidSettings() )
169  {
170  mPixmap = QPixmap();
171  update();
172  return; // makes no sense to render anything
173  }
174 
175  if ( mJob )
176  {
177  QgsDebugMsg( QStringLiteral( "oveview - canceling old" ) );
178  mJob->cancel();
179  QgsDebugMsg( QStringLiteral( "oveview - deleting old" ) );
180  delete mJob; // get rid of previous job (if any)
181  }
182 
183  QgsDebugMsg( QStringLiteral( "oveview - starting new" ) );
184 
185  // TODO: setup overview mode
188  mJob->start();
189 
191 
192  // schedule repaint
193  update();
194 
195  // update panning widget
196  drawExtentRect();
197 }
198 
200 {
201  QgsDebugMsg( QStringLiteral( "overview - finished" ) );
202  mPixmap = QPixmap::fromImage( mJob->renderedImage() );
203 
204  delete mJob;
205  mJob = nullptr;
206 
207  // schedule repaint
208  update();
209 }
210 
212 {
213  if ( !deferred )
214  refresh();
215 }
216 
217 
218 void QgsMapOverviewCanvas::setBackgroundColor( const QColor &color )
219 {
220  mSettings.setBackgroundColor( color );
221 
222  // set erase color
223  QPalette palette;
224  palette.setColor( backgroundRole(), color );
225  setPalette( palette );
226 }
227 
228 void QgsMapOverviewCanvas::setLayers( const QList<QgsMapLayer *> &layers )
229 {
230  const auto oldLayers = mSettings.layers();
231  for ( QgsMapLayer *ml : oldLayers )
232  {
234  }
235 
236  mSettings.setLayers( layers );
237 
238  const auto newLayers = mSettings.layers();
239  for ( QgsMapLayer *ml : newLayers )
240  {
242  }
243 
245 
246  refresh();
247 }
248 
250 {
251  QgsRectangle rect;
252  if ( mSettings.hasValidSettings() )
253  rect = mSettings.fullExtent();
254  else
255  rect = mMapCanvas->fullExtent();
256 
257  // expand a bit to keep features on margin
258  rect.scale( 1.1 );
259 
260  mSettings.setExtent( rect );
261  drawExtentRect();
262 }
263 
265 {
267 }
268 
270 {
272 }
273 
274 QList<QgsMapLayer *> QgsMapOverviewCanvas::layers() const
275 {
276  return mSettings.layers();
277 }
278 
279 
281 
282 QgsPanningWidget::QgsPanningWidget( QWidget *parent )
283  : QWidget( parent )
284 {
285  setObjectName( QStringLiteral( "panningWidget" ) );
286  setMinimumSize( 5, 5 );
287  setAttribute( Qt::WA_NoSystemBackground );
288 }
289 
290 void QgsPanningWidget::setPolygon( const QPolygon &p )
291 {
292  if ( p == mPoly ) return;
293  mPoly = p;
294 
295  //ensure polygon is closed
296  if ( mPoly.at( 0 ) != mPoly.at( mPoly.length() - 1 ) )
297  mPoly.append( mPoly.at( 0 ) );
298 
299  setGeometry( p.boundingRect() );
300  update();
301 }
302 
303 void QgsPanningWidget::paintEvent( QPaintEvent *pe )
304 {
305  Q_UNUSED( pe )
306 
307  QPainter p;
308  p.begin( this );
309  p.setPen( Qt::red );
310  QPolygonF t = mPoly.translated( -mPoly.boundingRect().left(), -mPoly.boundingRect().top() );
311 
312  // drawPolygon causes issues on windows - corners of path may be missing resulting in triangles being drawn
313  // instead of rectangles! (Same cause as #13343)
314  QPainterPath path;
315  path.addPolygon( t );
316  p.drawPath( path );
317 
318  p.end();
319 }
320 
321 
322 
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:41
Base class for all map layer types.
Definition: qgsmaplayer.h:78
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.
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the coordinate transform context, which stores various information regarding which datum transfo...
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
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.
Definition: qgsrectangle.h:235
QgsMapCanvas * mMapCanvas
main map canvas - used to get/set extent
QgsMapRendererQImageJob * mJob
for rendering overview
QColor backgroundColor() const
Gets 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
Gets list of layers for map rendering The layers are stored in the reverse order of how they are rend...
void setBackgroundColor(const QColor &color)
changes background color
virtual QImage renderedImage()=0
Gets a preview/resulting image.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:73
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:37
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.h:148
void setOutputSize(QSize size)
Sets 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.
Definition: qgsrectangle.h:426
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
void transformContextChanged()
Emitted when the canvas transform context is changed.
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
Gets access to properties used for map rendering.
Job implementation that renders everything sequentially in one thread.
void setBackgroundColor(const QColor &color)
Sets 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
Returns 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 transformContextChanged()
Called when the canvas transform context is changed.
void extentsChanged()
Emitted when the extents of the map change.
QgsPointXY toMapCoordinates(int x, int y) const
Transform device coordinates to map (world) coordinates.
void drawExtentRect()
used for overview canvas to reflect changed extent in main map canvas