QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 
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  {
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 }
double mTranslationOffsetY
A cross is used to highlight points (x)
Definition: qgsrubberband.h:51
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.
GeometryType
Definition: qgis.h:155
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:38
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.
int numberOfVertices() const
Returns count of vertices in all lists of mPoint.
A cross is used to highlight points (+)
Definition: qgsrubberband.h:47
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:110
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:33
void combineExtentWith(QgsRectangle *rect)
expand the rectangle so that covers both the original rectangle and the given rectangle ...
QList< QList< QgsPoint > > mPoints
Nested lists used for multitypes.
A circle is used to highlight points (○)
Definition: qgsrubberband.h:59
QGis::GeometryType mGeometryType
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:53
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:47
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 file 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:44
void setToGeometry(QgsGeometry *geom, QgsVectorLayer *layer)
Sets this rubber band to the geometry of an existing feature.
static QgsPolyline getPolyline(const QList< QgsPoint > &points)
IconType mIconType
Icon to be shown.
A class to represent a point geometry.
Definition: qgspoint.h:63
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:50
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 ...
A box is used to highlight points (□)
Definition: qgsrubberband.h:55
int size() const
Returns number of geometries.
void setToCanvasRectangle(const QRect &rect)
Sets this rubber band to a map canvas rectangle.
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
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:118
void setColor(const QColor &color)
Set the color for the rubberband.
double mTranslationOffsetX
No icon is used.
Definition: qgsrubberband.h:43
static QgsGeometry * fromPolygon(const QgsPolygon &polygon)
construct geometry from a polygon
int mIconSize
The size of the icon for points.
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.
IconType
Icons Added in 1.9.
Definition: qgsrubberband.h:38
void updateRect()
recalculates needed rectangle
A full box is used to highlight points (■)
Definition: qgsrubberband.h:63