QGIS API Documentation  2.99.0-Master (64819bc)
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.h>
32 
33 
35  : QWidget( parent )
36  , mMapCanvas( mapCanvas )
37  , mJob( nullptr )
38 {
39  setAutoFillBackground( true );
40  setObjectName( QStringLiteral( "theOverviewCanvas" ) );
41  mPanningWidget = new QgsPanningWidget( this );
42 
44 
48 }
49 
50 void QgsMapOverviewCanvas::resizeEvent( QResizeEvent* e )
51 {
52  mPixmap = QPixmap();
53 
54  mSettings.setOutputSize( e->size() );
55 
57 
58  refresh();
59 
60  QWidget::resizeEvent( e );
61 }
62 
63 void QgsMapOverviewCanvas::showEvent( QShowEvent* e )
64 {
65  refresh();
66  QWidget::showEvent( e );
67 }
68 
69 void QgsMapOverviewCanvas::paintEvent( QPaintEvent* pe )
70 {
71  if ( !mPixmap.isNull() )
72  {
73  QPainter paint( this );
74  paint.drawPixmap( pe->rect().topLeft(), mPixmap, pe->rect() );
75  }
76 }
77 
78 
80 {
81  if ( !mMapCanvas ) return;
82 
83  const QgsRectangle& extent = mMapCanvas->extent();
84 
85  // show only when valid extent is set
86  if ( extent.isEmpty() || mSettings.visibleExtent().isEmpty() )
87  {
88  mPanningWidget->hide();
89  return;
90  }
91 
92  const QPolygonF& vPoly = mMapCanvas->mapSettings().visiblePolygon();
93  const QgsMapToPixel& cXf = mSettings.mapToPixel();
94  QVector< QPoint > pts;
95  pts.push_back( cXf.transform( QgsPoint( vPoly[0] ) ).toQPointF().toPoint() );
96  pts.push_back( cXf.transform( QgsPoint( vPoly[1] ) ).toQPointF().toPoint() );
97  pts.push_back( cXf.transform( QgsPoint( vPoly[2] ) ).toQPointF().toPoint() );
98  pts.push_back( cXf.transform( QgsPoint( vPoly[3] ) ).toQPointF().toPoint() );
99  mPanningWidget->setPolygon( QPolygon( pts ) );
100  mPanningWidget->show(); // show if hidden
101 }
102 
103 
105 {
106 // if (mPanningWidget->isHidden())
107 // return;
108 
109  // set offset in panning widget if inside it
110  // for better experience with panning :)
111  if ( mPanningWidget->geometry().contains( e->pos() ) )
112  {
113  mPanningCursorOffset = e->pos() - mPanningWidget->pos();
114  }
115  else
116  {
117  // use center of the panning widget if outside
118  QSize s = mPanningWidget->size();
119  mPanningCursorOffset = QPoint( s.width() / 2, s.height() / 2 );
120  }
121  updatePanningWidget( e->pos() );
122 }
123 
124 
126 {
127 // if (mPanningWidget->isHidden())
128 // return;
129 
130  if ( e->button() == Qt::LeftButton )
131  {
132  // set new extent
133  const QgsMapToPixel& cXf = mSettings.mapToPixel();
134  QRect rect = mPanningWidget->geometry();
135 
136  QgsPoint center = cXf.toMapCoordinates( rect.center() );
137  mMapCanvas->setCenter( center );
138  mMapCanvas->refresh();
139  }
140 }
141 
142 
144 {
145  // move with panning widget if tracking cursor
146  if (( e->buttons() & Qt::LeftButton ) == Qt::LeftButton )
147  {
148  updatePanningWidget( e->pos() );
149  }
150 }
151 
152 
154 {
155 // if (mPanningWidget->isHidden())
156 // return;
157  mPanningWidget->move( pos.x() - mPanningCursorOffset.x(), pos.y() - mPanningCursorOffset.y() );
158 }
159 
161 {
162  if ( !isVisible() )
163  return;
164 
166 
167  if ( !mSettings.hasValidSettings() )
168  {
169  mPixmap = QPixmap();
170  update();
171  return; // makes no sense to render anything
172  }
173 
174  if ( mJob )
175  {
176  QgsDebugMsg( "oveview - canceling old" );
177  mJob->cancel();
178  QgsDebugMsg( "oveview - deleting old" );
179  delete mJob; // get rid of previous job (if any)
180  }
181 
182  QgsDebugMsg( "oveview - starting new" );
183 
184  // TODO: setup overview mode
186  connect( mJob, SIGNAL( finished() ), this, SLOT( mapRenderingFinished() ) );
187  mJob->start();
188 
190 
191  // schedule repaint
192  update();
193 
194  // update panning widget
195  drawExtentRect();
196 }
197 
199 {
200  QgsDebugMsg( "overview - finished" );
201  mPixmap = QPixmap::fromImage( mJob->renderedImage() );
202 
203  delete mJob;
204  mJob = nullptr;
205 
206  // schedule repaint
207  update();
208 }
209 
211 {
212  if ( !deferred )
213  refresh();
214 }
215 
216 
217 void QgsMapOverviewCanvas::setBackgroundColor( const QColor& color )
218 {
219  mSettings.setBackgroundColor( color );
220 
221  // set erase color
222  QPalette palette;
223  palette.setColor( backgroundRole(), color );
224  setPalette( palette );
225 }
226 
227 void QgsMapOverviewCanvas::setLayers( const QList<QgsMapLayer*>& layers )
228 {
229  Q_FOREACH ( QgsMapLayer* ml, mSettings.layers() )
230  {
232  }
233 
234  mSettings.setLayers( layers );
235 
236  Q_FOREACH ( QgsMapLayer* ml, mSettings.layers() )
237  {
239  }
240 
242 
243  refresh();
244 }
245 
247 {
248  QgsRectangle rect;
249  if ( mSettings.hasValidSettings() )
250  rect = mSettings.fullExtent();
251  else
252  rect = mMapCanvas->fullExtent();
253 
254  // expand a bit to keep features on margin
255  rect.scale( 1.1 );
256 
257  mSettings.setExtent( rect );
258  drawExtentRect();
259 }
260 
262 {
264 }
265 
267 {
269 }
270 
271 QList<QgsMapLayer*> QgsMapOverviewCanvas::layers() const
272 {
273  return mSettings.layers();
274 }
275 
276 
278 
279 QgsPanningWidget::QgsPanningWidget( QWidget* parent )
280  : QWidget( parent )
281 {
282  setObjectName( QStringLiteral( "panningWidget" ) );
283  setMinimumSize( 5, 5 );
284  setAttribute( Qt::WA_NoSystemBackground );
285 }
286 
287 void QgsPanningWidget::setPolygon( const QPolygon& p )
288 {
289  if ( p == mPoly ) return;
290  mPoly = p;
291 
292  //ensure polygon is closed
293  if ( mPoly.at( 0 ) != mPoly.at( mPoly.length() - 1 ) )
294  mPoly.append( mPoly.at( 0 ) );
295 
296  setGeometry( p.boundingRect() );
297  update();
298 }
299 
300 void QgsPanningWidget::paintEvent( QPaintEvent* pe )
301 {
302  Q_UNUSED( pe );
303 
304  QPainter p;
305  p.begin( this );
306  p.setPen( Qt::red );
307  QPolygonF t = mPoly.translated( -mPoly.boundingRect().left(), -mPoly.boundingRect().top() );
308 
309  // drawPolygon causes issues on windows - corners of path may be missing resulting in triangles being drawn
310  // instead of rectangles! (Same cause as #13343)
311  QPainterPath path;
312  path.addPolygon( t );
313  p.drawPath( path );
314 
315  p.end();
316 }
317 
318 
319 
QPoint mPanningCursorOffset
position of cursor inside panning widget
void layerRepaintRequested(bool deferred=false)
Triggered when a layer in the overview requests a repaint.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
A rectangle specified with double values.
Definition: qgsrectangle.h:36
Base class for all map layer types.
Definition: qgsmaplayer.h:52
void setExtent(const QgsRectangle &rect, bool magnified=true)
Set coordinates of the rectangle which should be rendered.
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspoint.cpp:158
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
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 scale(double scaleFactor, const QgsPoint *c=nullptr)
Scale the rectangle around its center point.
void updatePanningWidget(QPoint pos)
called when panning to reflect mouse movement
QgsPoint toMapCoordinates(int x, int y) const
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:72
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)
void hasCrsTransformEnabledChanged(bool flag)
Emitted when on-the-fly projection has been turned on/off.
QgsPoint transform(const QgsPoint &p) const
Transform the point from map (world) coordinates to device coordinates.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
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
test if 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
A class to represent a point.
Definition: qgspoint.h:143
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.
void hasCrsTransformEnabled(bool flag)
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.
void setCenter(const QgsPoint &center)
Set the center of the map canvas, in geographical coordinates.
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.
void drawExtentRect()
used for overview canvas to reflect changed extent in main map canvas
void setCrsTransformEnabled(bool enabled)
sets whether to use projections for this layer set