QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgsrubberband.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrubberband.cpp - Rubberband widget for drawing multilines and polygons
3  --------------------------------------
4  Date : 07-Jan-2006
5  Copyright : (C) 2006 by Tom Elwertowski
6  Email : telwertowski at users dot sourceforge dot net
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsrubberband.h"
17 #include "qgsfeature.h"
18 #include "qgsgeometry.h"
19 #include "qgslogger.h"
20 #include "qgsmapcanvas.h"
21 #include "qgsmaprenderer.h"
22 #include "qgsvectorlayer.h"
23 #include <QPainter>
24 
31  : QgsMapCanvasItem( mapCanvas )
32  , mIconSize( 5 )
33  , mIconType( ICON_CIRCLE )
34  , mGeometryType( geometryType )
35  , mTranslationOffsetX( 0.0 )
36  , mTranslationOffsetY( 0.0 )
37 {
38  reset( geometryType );
39  QColor color( Qt::lightGray );
40  color.setAlpha( 63 );
41  setColor( color );
42  setWidth( 1 );
43  setLineStyle( Qt::SolidLine );
44  setBrushStyle( Qt::SolidPattern );
45 }
46 
47 QgsRubberBand::QgsRubberBand( QgsMapCanvas* mapCanvas, bool isPolygon )
48  : QgsMapCanvasItem( mapCanvas )
49  , mIconSize( 5 )
50  , mIconType( ICON_CIRCLE )
51  , mTranslationOffsetX( 0.0 )
52  , mTranslationOffsetY( 0.0 )
53 {
54  reset( isPolygon ? QGis::Polygon : QGis::Line );
55  QColor color( Qt::lightGray );
56  color.setAlpha( 63 );
57  setColor( color );
58  setWidth( 1 );
59  setLineStyle( Qt::SolidLine );
60  setBrushStyle( Qt::SolidPattern );
61 }
62 
63 QgsRubberBand::QgsRubberBand(): QgsMapCanvasItem( 0 )
64 {
65 }
66 
68 {
69 }
70 
74 void QgsRubberBand::setColor( const QColor & color )
75 {
76  setBorderColor( color );
77  setFillColor( color );
78 }
79 
83 void QgsRubberBand::setFillColor( const QColor & color )
84 {
85  QColor fillColor( color.red(), color.green(), color.blue(), color.alpha() );
86  mBrush.setColor( fillColor );
87 }
88 
92 void QgsRubberBand::setBorderColor( const QColor & color )
93 {
94  QColor penColor( color.red(), color.green(), color.blue(), color.alpha() );
95  mPen.setColor( penColor );
96 }
97 
98 
102 void QgsRubberBand::setWidth( int width )
103 {
104  mPen.setWidth( width );
105 }
106 
108 {
109  mIconType = icon;
110 }
111 
112 void QgsRubberBand::setIconSize( int iconSize )
113 {
114  mIconSize = iconSize;
115 }
116 
117 void QgsRubberBand::setLineStyle( Qt::PenStyle penStyle )
118 {
119  mPen.setStyle( penStyle );
120 }
121 
122 void QgsRubberBand::setBrushStyle( Qt::BrushStyle brushStyle )
123 {
124  mBrush.setStyle( brushStyle );
125 }
126 
131 {
132  mPoints.clear();
133  mGeometryType = geometryType;
134  updateRect();
135  update();
136 }
137 
138 void QgsRubberBand::reset( bool isPolygon )
139 {
140  mPoints.clear();
141  mGeometryType = isPolygon ? QGis::Polygon : QGis::Line;
142  updateRect();
143  update();
144 }
145 
149 void QgsRubberBand::addPoint( const QgsPoint & p, bool doUpdate /* = true */, int geometryIndex )
150 {
151  if ( geometryIndex < 0 )
152  {
153  geometryIndex = mPoints.size() - 1;
154  }
155 
156  if ( geometryIndex < 0 || geometryIndex > mPoints.size() )
157  {
158  return;
159  }
160 
161  if ( geometryIndex == mPoints.size() )
162  {
163  mPoints.push_back( QList<QgsPoint>() << p );
164  }
165 
166  if ( mPoints[geometryIndex].size() == 2 &&
167  mPoints[geometryIndex][0] == mPoints[geometryIndex][1] )
168  {
169  mPoints[geometryIndex].last() = p;
170  }
171  else
172  {
173  mPoints[geometryIndex] << p;
174  }
175 
176 
177  if ( doUpdate )
178  {
179  updateRect();
180  update();
181  }
182 }
183 
184 
185 void QgsRubberBand::removePoint( int index, bool doUpdate/* = true*/, int geometryIndex/* = 0*/ )
186 {
187 
188  if ( mPoints.size() < geometryIndex + 1 )
189  {
190  return;
191  }
192 
193 
194  if ( mPoints[geometryIndex].size() > 0 )
195  {
196  // negative index removes from end, eg -1 removes last one
197  if ( index < 0 )
198  {
199  index = mPoints[geometryIndex].size() + index;
200  }
201  mPoints[geometryIndex].removeAt( index );
202  }
203 
204  if ( doUpdate )
205  {
206  updateRect();
207  update();
208  }
209 }
210 
211 void QgsRubberBand::removeLastPoint( int geometryIndex, bool doUpdate/* = true*/ )
212 {
213  removePoint( -1, doUpdate, geometryIndex );
214 }
215 
219 void QgsRubberBand::movePoint( const QgsPoint & p, int geometryIndex )
220 {
221  if ( mPoints.size() < geometryIndex + 1 )
222  {
223  return;
224  }
225 
226  if ( mPoints.at( geometryIndex ).size() < 1 )
227  {
228  return;
229  }
230 
231  mPoints[geometryIndex].last() = p;
232 
233  updateRect();
234  update();
235 }
236 
237 void QgsRubberBand::movePoint( int index, const QgsPoint& p, int geometryIndex )
238 {
239  if ( mPoints.size() < geometryIndex + 1 )
240  {
241  return;
242  }
243 
244  if ( mPoints.at( geometryIndex ).size() < index )
245  {
246  return;
247  }
248 
249  mPoints[geometryIndex][index] = p;
250 
251  updateRect();
252  update();
253 }
254 
256 {
257  if ( !geom )
258  {
259  reset( mGeometryType );
260  return;
261  }
262 
263  reset( geom->type() );
264  addGeometry( geom, layer );
265 }
266 
268 {
269  if ( !geom )
270  {
271  return;
272  }
273 
274  //maprender object of canvas
275  const QgsMapSettings& ms = mMapCanvas->mapSettings();
276 
277  int idx = mPoints.size();
278 
279  switch ( geom->wkbType() )
280  {
281 
282  case QGis::WKBPoint:
283  case QGis::WKBPoint25D:
284  {
285  QgsPoint pt;
286  if ( layer )
287  {
288  pt = ms.layerToMapCoordinates( layer, geom->asPoint() );
289  }
290  else
291  {
292  pt = geom->asPoint();
293  }
294  addPoint( pt, false, idx );
295  removeLastPoint( idx, false );
296  }
297  break;
298 
299  case QGis::WKBMultiPoint:
301  {
302  QgsMultiPoint mpt = geom->asMultiPoint();
303  for ( int i = 0; i < mpt.size(); ++i, ++idx )
304  {
305  QgsPoint pt = mpt[i];
306  if ( layer )
307  {
308  addPoint( ms.layerToMapCoordinates( layer, pt ), false, idx );
309  removeLastPoint( idx, false );
310  }
311  else
312  {
313  addPoint( pt, false, idx );
314  removeLastPoint( idx, false );
315  }
316  }
317  }
318  break;
319 
320  case QGis::WKBLineString:
322  {
323  QgsPolyline line = geom->asPolyline();
324  for ( int i = 0; i < line.count(); i++ )
325  {
326  if ( layer )
327  {
328  addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx );
329  }
330  else
331  {
332  addPoint( line[i], false, idx );
333  }
334  }
335  }
336  break;
337 
340  {
341 
342  QgsMultiPolyline mline = geom->asMultiPolyline();
343  for ( int i = 0; i < mline.size(); ++i, ++idx )
344  {
345  QgsPolyline line = mline[i];
346 
347  if ( line.size() == 0 )
348  {
349  --idx;
350  }
351 
352  for ( int j = 0; j < line.size(); ++j )
353  {
354  if ( layer )
355  {
356  addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx );
357  }
358  else
359  {
360  addPoint( line[j], false, idx );
361  }
362  }
363  }
364  }
365  break;
366 
367  case QGis::WKBPolygon:
368  case QGis::WKBPolygon25D:
369  {
370  QgsPolygon poly = geom->asPolygon();
371  QgsPolyline line = poly[0];
372  for ( int i = 0; i < line.count(); i++ )
373  {
374  if ( layer )
375  {
376  addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx );
377  }
378  else
379  {
380  addPoint( line[i], false, idx );
381  }
382  }
383  }
384  break;
385 
388  {
389 
390  QgsMultiPolygon multipoly = geom->asMultiPolygon();
391  for ( int i = 0; i < multipoly.size(); ++i, ++idx )
392  {
393  QgsPolygon poly = multipoly[i];
394  QgsPolyline line = poly[0];
395  for ( int j = 0; j < line.count(); ++j )
396  {
397  if ( layer )
398  {
399  addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx );
400  }
401  else
402  {
403  addPoint( line[j], false, idx );
404  }
405  }
406  }
407  }
408  break;
409 
410  case QGis::WKBUnknown:
411  default:
412  return;
413  }
414 
415  updateRect();
416  update();
417 }
418 
419 void QgsRubberBand::setToCanvasRectangle( const QRect& rect )
420 {
421  if ( !mMapCanvas )
422  {
423  return;
424  }
425 
426  const QgsMapToPixel* transform = mMapCanvas->getCoordinateTransform();
427  QgsPoint ll = transform->toMapCoordinates( rect.left(), rect.bottom() );
428  QgsPoint lr = transform->toMapCoordinates( rect.right(), rect.bottom() );
429  QgsPoint ul = transform->toMapCoordinates( rect.left(), rect.top() );
430  QgsPoint ur = transform->toMapCoordinates( rect.right(), rect.top() );
431 
432  reset( QGis::Polygon );
433  addPoint( ll, false );
434  addPoint( lr, false );
435  addPoint( ur, false );
436  addPoint( ul, true );
437 }
438 
442 void QgsRubberBand::paint( QPainter* p )
443 {
444  if ( mPoints.size() > 0 )
445  {
446  p->setBrush( mBrush );
447  p->setPen( mPen );
448 
449  Q_FOREACH ( const QList<QgsPoint>& line, mPoints )
450  {
451  QVector<QPointF> pts;
452  Q_FOREACH ( const QgsPoint& pt, line )
453  {
454  const QPointF cur = toCanvasCoordinates( QgsPoint( pt.x() + mTranslationOffsetX, pt.y() + mTranslationOffsetY ) ) - pos();
455  if ( pts.empty() || std::abs( pts.back().x() - cur.x() ) > 1 || std::abs( pts.back().y() - cur.y() ) > 1 )
456  pts.append( cur );
457  }
458 
459  switch ( mGeometryType )
460  {
461  case QGis::Polygon:
462  {
463  p->drawPolygon( pts );
464  }
465  break;
466 
467  case QGis::Point:
468  {
469  Q_FOREACH ( const QPointF& pt, pts )
470  {
471  double x = pt.x();
472  double y = pt.y();
473 
474  qreal s = ( mIconSize - 1 ) / 2;
475 
476  switch ( mIconType )
477  {
478  case ICON_NONE:
479  break;
480 
481  case ICON_CROSS:
482  p->drawLine( QLineF( x - s, y, x + s, y ) );
483  p->drawLine( QLineF( x, y - s, x, y + s ) );
484  break;
485 
486  case ICON_X:
487  p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
488  p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
489  break;
490 
491  case ICON_BOX:
492  p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
493  p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
494  p->drawLine( QLineF( x + s, y + s, x - s, y + s ) );
495  p->drawLine( QLineF( x - s, y + s, x - s, y - s ) );
496  break;
497 
498  case ICON_FULL_BOX:
499  p->drawRect( x - s, y - s, mIconSize, mIconSize );
500  break;
501 
502  case ICON_CIRCLE:
503  p->drawEllipse( x - s, y - s, mIconSize, mIconSize );
504  break;
505  }
506  }
507  }
508  break;
509 
510  case QGis::Line:
511  default:
512  {
513  p->drawPolyline( pts );
514  }
515  break;
516  }
517  }
518  }
519 }
520 
522 {
523  if ( mPoints.empty() )
524  {
525  setRect( QgsRectangle() );
526  setVisible( false );
527  return;
528  }
529 
530  const QgsMapToPixel& m2p = *( mMapCanvas->getCoordinateTransform() );
531 
532  qreal w = ( mIconSize - 1 ) / 2 + mPen.width();
533 
534  QgsRectangle r;
535  for ( int i = 0; i < mPoints.size(); ++i )
536  {
537  QList<QgsPoint>::const_iterator it = mPoints.at( i ).constBegin(),
538  itE = mPoints.at( i ).constEnd();
539  for ( ; it != itE; ++it )
540  {
541  QgsPoint p( it->x() + mTranslationOffsetX, it->y() + mTranslationOffsetY );
542  p = m2p.transform( p );
543  QgsRectangle rect( p.x() - w, p.y() - w, p.x() + w, p.y() + w );
544  r.combineExtentWith( &rect );
545  }
546  }
547 
548  // This is an hack to pass QgsMapCanvasItem::setRect what it
549  // expects (encoding of position and size of the item)
550  QgsPoint topLeft = m2p.toMapPoint( r.xMinimum(), r.yMinimum() );
551  double res = m2p.mapUnitsPerPixel();
552  QgsRectangle rect( topLeft.x(), topLeft.y(), topLeft.x() + r.width()*res, topLeft.y() - r.height()*res );
553 
554  setRect( rect );
555  setVisible( true );
556 }
557 
559 {
560  // nothing to do here...
561 }
562 
563 void QgsRubberBand::setTranslationOffset( double dx, double dy )
564 {
565  mTranslationOffsetX = dx;
566  mTranslationOffsetY = dy;
567  updateRect();
568 }
569 
571 {
572  return mPoints.size();
573 }
574 
575 int QgsRubberBand::partSize( int geometryIndex ) const
576 {
577  if ( geometryIndex < 0 || geometryIndex >= mPoints.size() ) return 0;
578  return mPoints[geometryIndex].size();
579 }
580 
582 {
583  int count = 0;
584  QList<QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
585  for ( ; it != mPoints.constEnd(); ++it )
586  {
587  QList<QgsPoint>::const_iterator iter = it->constBegin();
588  for ( ; iter != it->constEnd(); ++iter )
589  {
590  ++count;
591  }
592  }
593  return count;
594 }
595 
596 const QgsPoint *QgsRubberBand::getPoint( int i, int j ) const
597 {
598  if ( i < mPoints.size() && j < mPoints[i].size() )
599  return &mPoints[i][j];
600  else
601  return 0;
602 }
603 
605 {
606  QgsGeometry *geom = NULL;
607 
608  switch ( mGeometryType )
609  {
610  case QGis::Polygon:
611  {
612  QgsPolygon polygon;
613  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
614  for ( ; it != mPoints.constEnd(); ++it )
615  {
616  polygon.append( getPolyline( *it ) );
617  }
618  geom = QgsGeometry::fromPolygon( polygon );
619  break;
620  }
621 
622  case QGis::Point:
623  {
624  QgsMultiPoint multiPoint;
625 
626  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
627  for ( ; it != mPoints.constEnd(); ++it )
628  {
629  multiPoint += getPolyline( *it );
630  }
631  geom = QgsGeometry::fromMultiPoint( multiPoint );
632  break;
633  }
634 
635  case QGis::Line:
636  default:
637  {
638  if ( mPoints.size() > 0 )
639  {
640  if ( mPoints.size() > 1 )
641  {
642  QgsMultiPolyline multiPolyline;
643  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
644  for ( ; it != mPoints.constEnd(); ++it )
645  {
646  multiPolyline.append( getPolyline( *it ) );
647  }
648  geom = QgsGeometry::fromMultiPolyline( multiPolyline );
649  }
650  else
651  {
652  geom = QgsGeometry::fromPolyline( getPolyline( mPoints[0] ) );
653  }
654  }
655  break;
656  }
657  }
658  return geom;
659 }
660 
661 QgsPolyline QgsRubberBand::getPolyline( const QList<QgsPoint> & points )
662 {
663  QgsPolyline polyline;
664  QList<QgsPoint>::const_iterator iter = points.constBegin();
665  for ( ; iter != points.constEnd(); ++iter )
666  {
667  polyline.append( *iter );
668  }
669  return polyline;
670 }
void setIconSize(int iconSize)
Set the size of the point icons.
void setWidth(int width)
Set the width of the line.
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
QgsPoint layerToMapCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from layer's CRS to output CRS
void setBorderColor(const QColor &color)
Set the border color for the rubberband.
QPointF toCanvasCoordinates(const QgsPoint &point) const
transformation from map coordinates to screen coordinates
void setTranslationOffset(double dx, double dy)
Adds translation to original coordinates (all in map coordinates)
void setLineStyle(Qt::PenStyle penStyle)
Set the style of the line.
QgsMultiPolyline asMultiPolyline() const
return contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list
void movePoint(const QgsPoint &p, int geometryIndex=0)
Moves the rubber band point specified by index.
QVector< QgsPoint > QgsPolyline
polyline is represented as a vector of points
Definition: qgsgeometry.h:33
A box is used to highlight points (□)
Definition: qgsrubberband.h:54
QgsPolygon asPolygon() const
return contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list ...
QgsPoint transform(const QgsPoint &p) const
const QgsPoint * getPoint(int i, int j=0) const
Return vertex.
An abstract class for items that can be placed on the map canvas.
QGis::GeometryType type() const
Returns type of the vector.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
GeometryType
Definition: qgis.h:155
virtual void updatePosition() override
called on changed extent or resize event to update position of the item
int numberOfVertices() const
Returns count of vertices in all lists of mPoint.
QgsRectangle rect() const
returns canvas item rectangle in map units
QgsGeometry * asGeometry()
Returns the rubberband as a Geometry.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:105
double x() const
Definition: qgspoint.h:126
virtual void paint(QPainter *p) override
QgsMultiPolygon asMultiPolygon() const
return contents of the geometry as a multi polygon if wkbType is WKBMultiPolygon, otherwise an empty ...
The QgsMapSettings class contains configuration for rendering of the map.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
void combineExtentWith(QgsRectangle *rect)
expand the rectangle so that covers both the original rectangle and the given rectangle ...
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:193
A circle is used to highlight points (○)
Definition: qgsrubberband.h:58
void removePoint(int index=0, bool doUpdate=true, int geometryIndex=0)
Remove a vertex from the rubberband and (optionally) update canvas.
void setRect(const QgsRectangle &r, bool resetRotation=true)
sets canvas item rectangle in map units
QVector< QgsPolygon > QgsMultiPolygon
a collection of QgsPolygons that share a common collection of attributes
Definition: qgsgeometry.h:48
void addPoint(const QgsPoint &p, bool doUpdate=true, int geometryIndex=0)
Add a vertex to the rubberband and update canvas.
QVector< QgsPoint > QgsMultiPoint
a collection of QgsPoints that share a common collection of attributes
Definition: qgsgeometry.h:42
void reset(QGis::GeometryType geometryType=QGis::Line)
Clears all the geometries in this rubberband.
QGis::WkbType wkbType() const
Returns type of wkb (point / linestring / polygon etc.)
double mapUnitsPerPixel() const
Return current map units per pixel.
void setFillColor(const QColor &color)
Set the fill color for the rubberband.
QVector< QgsPolyline > QgsPolygon
polygon: first item of the list is outer ring, inner rings (if any) start from second item ...
Definition: qgsgeometry.h:39
void setToGeometry(QgsGeometry *geom, QgsVectorLayer *layer)
Sets this rubber band to the geometry of an existing feature.
A cross is used to highlight points (x)
Definition: qgsrubberband.h:50
A class to represent a point.
Definition: qgspoint.h:63
A full box is used to highlight points (■)
Definition: qgsrubberband.h:62
void setBrushStyle(Qt::BrushStyle brushStyle)
Set the style of the brush.
QVector< QgsPolyline > QgsMultiPolyline
a collection of QgsPolylines that share a common collection of attributes
Definition: qgsgeometry.h:45
static QgsGeometry * fromMultiPolyline(const QgsMultiPolyline &multiline)
construct geometry from a multipolyline
QgsPoint toMapCoordinates(int x, int y) const
void setIcon(IconType icon)
Set the icon type to highlight point geometries.
QgsPolyline asPolyline() const
return contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list ...
int size() const
Returns number of geometries.
void setToCanvasRectangle(const QRect &rect)
Sets this rubber band to a map canvas rectangle.
QgsRubberBand(QgsMapCanvas *mapCanvas, QGis::GeometryType geometryType=QGis::Line)
Creates a new RubberBand.
QgsMultiPoint asMultiPoint() const
return contents of the geometry as a multi point if wkbType is WKBMultiPoint, otherwise an empty list...
QgsMapCanvas * mMapCanvas
pointer to map canvas
int partSize(int geometryIndex) const
Returns number of vertices in feature part.
A cross is used to highlight points (+)
Definition: qgsrubberband.h:46
const QgsMapToPixel * getCoordinateTransform()
Get the current coordinate transform.
static QgsGeometry * fromMultiPoint(const QgsMultiPoint &multipoint)
construct geometry from a multipoint
static QgsGeometry * fromPolyline(const QgsPolyline &polyline)
construct geometry from a polyline
double y() const
Definition: qgspoint.h:134
No icon is used.
Definition: qgsrubberband.h:42
void setColor(const QColor &color)
Set the color for the rubberband.
static QgsGeometry * fromPolygon(const QgsPolygon &polygon)
construct geometry from a polygon
void addGeometry(QgsGeometry *geom, QgsVectorLayer *layer)
Add the geometry of an existing feature to a rubberband This is useful for multi feature highlighting...
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:198
QgsPoint asPoint() const
return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
Represents a vector layer which manages a vector based data sets.
void removeLastPoint(int geometryIndex=0, bool doUpdate=true)
Removes the last point.
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:183
void updateRect()
recalculates needed rectangle
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:203
QgsPoint toMapPoint(double x, double y) const