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 ur = transform->toMapCoordinates( rect.right(), rect.top() );
429 
430  reset( QGis::Polygon );
431  addPoint( ll, false );
432  addPoint( QgsPoint( ur.x(), ll.y() ), false );
433  addPoint( ur, false );
434  addPoint( QgsPoint( ll.x(), ur.y() ), true );
435 }
436 
440 void QgsRubberBand::paint( QPainter* p )
441 {
442  if ( mPoints.size() > 0 )
443  {
444  p->setBrush( mBrush );
445  p->setPen( mPen );
446 
447  Q_FOREACH ( const QList<QgsPoint>& line, mPoints )
448  {
449  QVector<QPointF> pts;
450  Q_FOREACH ( const QgsPoint& pt, line )
451  {
452  const QPointF cur = toCanvasCoordinates( QgsPoint( pt.x() + mTranslationOffsetX, pt.y() + mTranslationOffsetY ) ) - pos();
453  if ( pts.empty() || std::abs( pts.back().x() - cur.x() ) > 1 || std::abs( pts.back().y() - cur.y() ) > 1 )
454  pts.append( cur );
455  }
456 
457  switch ( mGeometryType )
458  {
459  case QGis::Polygon:
460  {
461  p->drawPolygon( pts );
462  }
463  break;
464 
465  case QGis::Point:
466  {
467  Q_FOREACH ( const QPointF& pt, pts )
468  {
469  double x = pt.x();
470  double y = pt.y();
471 
472  qreal s = ( mIconSize - 1 ) / 2;
473 
474  switch ( mIconType )
475  {
476  case ICON_NONE:
477  break;
478 
479  case ICON_CROSS:
480  p->drawLine( QLineF( x - s, y, x + s, y ) );
481  p->drawLine( QLineF( x, y - s, x, y + s ) );
482  break;
483 
484  case ICON_X:
485  p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
486  p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
487  break;
488 
489  case ICON_BOX:
490  p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
491  p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
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  break;
495 
496  case ICON_FULL_BOX:
497  p->drawRect( x - s, y - s, mIconSize, mIconSize );
498  break;
499 
500  case ICON_CIRCLE:
501  p->drawEllipse( x - s, y - s, mIconSize, mIconSize );
502  break;
503  }
504  }
505  }
506  break;
507 
508  case QGis::Line:
509  default:
510  {
511  p->drawPolyline( pts );
512  }
513  break;
514  }
515  }
516  }
517 }
518 
520 {
521  if ( mPoints.size() > 0 )
522  {
523  //initial point
524  QList<QgsPoint>::const_iterator it = mPoints.at( 0 ).constBegin();
525  if ( it == mPoints.at( 0 ).constEnd() )
526  {
527  return;
528  }
529 
530  qreal scale = mMapCanvas->mapUnitsPerPixel();
531  qreal s = ( mIconSize - 1 ) / 2 * scale;
532  qreal p = mPen.width() * scale;
533 
534  QgsRectangle r( it->x() + mTranslationOffsetX - s - p, it->y() + mTranslationOffsetY - s - p,
535  it->x() + mTranslationOffsetX + s + p, it->y() + mTranslationOffsetY + s + p );
536 
537  for ( int i = 0; i < mPoints.size(); ++i )
538  {
539  QList<QgsPoint>::const_iterator it = mPoints.at( i ).constBegin();
540  for ( ; it != mPoints.at( i ).constEnd(); ++it )
541  {
542  QgsRectangle rect = QgsRectangle( it->x() + mTranslationOffsetX - s - p, it->y() + mTranslationOffsetY - s - p,
543  it->x() + mTranslationOffsetX + s + p, it->y() + mTranslationOffsetY + s + p );
544  r.combineExtentWith( &rect );
545  }
546  }
547  setRect( r );
548  }
549  else
550  {
551  setRect( QgsRectangle() );
552  }
553  setVisible( mPoints.size() > 0 );
554 }
555 
556 void QgsRubberBand::setTranslationOffset( double dx, double dy )
557 {
558  mTranslationOffsetX = dx;
559  mTranslationOffsetY = dy;
560  updateRect();
561 }
562 
564 {
565  return mPoints.size();
566 }
567 
568 int QgsRubberBand::partSize( int geometryIndex ) const
569 {
570  if ( geometryIndex < 0 || geometryIndex >= mPoints.size() ) return 0;
571  return mPoints[geometryIndex].size();
572 }
573 
575 {
576  int count = 0;
577  QList<QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
578  for ( ; it != mPoints.constEnd(); ++it )
579  {
580  QList<QgsPoint>::const_iterator iter = it->constBegin();
581  for ( ; iter != it->constEnd(); ++iter )
582  {
583  ++count;
584  }
585  }
586  return count;
587 }
588 
589 const QgsPoint *QgsRubberBand::getPoint( int i, int j ) const
590 {
591  if ( i < mPoints.size() && j < mPoints[i].size() )
592  return &mPoints[i][j];
593  else
594  return 0;
595 }
596 
598 {
599  QgsGeometry *geom = NULL;
600 
601  switch ( mGeometryType )
602  {
603  case QGis::Polygon:
604  {
605  QgsPolygon polygon;
606  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
607  for ( ; it != mPoints.constEnd(); ++it )
608  {
609  polygon.append( getPolyline( *it ) );
610  }
611  geom = QgsGeometry::fromPolygon( polygon );
612  break;
613  }
614 
615  case QGis::Point:
616  {
617  QgsMultiPoint multiPoint;
618 
619  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
620  for ( ; it != mPoints.constEnd(); ++it )
621  {
622  multiPoint += getPolyline( *it );
623  }
624  geom = QgsGeometry::fromMultiPoint( multiPoint );
625  break;
626  }
627 
628  case QGis::Line:
629  default:
630  {
631  if ( mPoints.size() > 0 )
632  {
633  if ( mPoints.size() > 1 )
634  {
635  QgsMultiPolyline multiPolyline;
636  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
637  for ( ; it != mPoints.constEnd(); ++it )
638  {
639  multiPolyline.append( getPolyline( *it ) );
640  }
641  geom = QgsGeometry::fromMultiPolyline( multiPolyline );
642  }
643  else
644  {
645  geom = QgsGeometry::fromPolyline( getPolyline( mPoints[0] ) );
646  }
647  }
648  break;
649  }
650  }
651  return geom;
652 }
653 
654 QgsPolyline QgsRubberBand::getPolyline( const QList<QgsPoint> & points )
655 {
656  QgsPolyline polyline;
657  QList<QgsPoint>::const_iterator iter = points.constBegin();
658  for ( ; iter != points.constEnd(); ++iter )
659  {
660  polyline.append( *iter );
661  }
662  return polyline;
663 }
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.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
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 ...
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()
Returns type of the vector.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
GeometryType
Definition: qgis.h:155
int numberOfVertices() const
Returns count of vertices in all lists of mPoint.
QgsRectangle rect() const
returns canvas item rectangle
static QIcon icon(QString icon)
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:104
double x() const
Definition: qgspoint.h:126
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 ...
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.
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.)
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
QPointF toCanvasCoordinates(const QgsPoint &point)
transformation from map coordinates to screen coordinates
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.
void setRect(const QgsRectangle &r)
sets canvas item rectangle
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...
virtual void paint(QPainter *p)
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.
void updateRect()
recalculates needed rectangle