QGIS API Documentation  2.3.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  mPen.setColor( color );
77  QColor fillColor( color.red(), color.green(), color.blue(), color.alpha() );
78  mBrush.setColor( fillColor );
79 }
80 
84 void QgsRubberBand::setWidth( int width )
85 {
86  mPen.setWidth( width );
87 }
88 
90 {
91  mIconType = icon;
92 }
93 
94 void QgsRubberBand::setIconSize( int iconSize )
95 {
96  mIconSize = iconSize;
97 }
98 
99 void QgsRubberBand::setLineStyle( Qt::PenStyle penStyle )
100 {
101  mPen.setStyle( penStyle );
102 }
103 
104 void QgsRubberBand::setBrushStyle( Qt::BrushStyle brushStyle )
105 {
106  mBrush.setStyle( brushStyle );
107 }
108 
113 {
114  mPoints.clear();
115  mGeometryType = geometryType;
116  updateRect();
117  update();
118 }
119 
120 void QgsRubberBand::reset( bool isPolygon )
121 {
122  mPoints.clear();
123  mGeometryType = isPolygon ? QGis::Polygon : QGis::Line;
124  updateRect();
125  update();
126 }
127 
131 void QgsRubberBand::addPoint( const QgsPoint & p, bool doUpdate /* = true */, int geometryIndex )
132 {
133  if ( geometryIndex < 0 )
134  {
135  geometryIndex = mPoints.size() - 1;
136  }
137 
138  if ( geometryIndex < 0 || geometryIndex > mPoints.size() )
139  {
140  return;
141  }
142 
143  if ( geometryIndex == mPoints.size() )
144  {
145  mPoints.push_back( QList<QgsPoint>() << p );
146  }
147 
148  if ( mPoints[geometryIndex].size() == 2 &&
149  mPoints[geometryIndex][0] == mPoints[geometryIndex][1] )
150  {
151  mPoints[geometryIndex].last() = p;
152  }
153  else
154  {
155  mPoints[geometryIndex] << p;
156  }
157 
158 
159  if ( doUpdate )
160  {
161  updateRect();
162  update();
163  }
164 }
165 
166 
167 void QgsRubberBand::removePoint( int index, bool doUpdate/* = true*/, int geometryIndex/* = 0*/ )
168 {
169 
170  if ( mPoints.size() < geometryIndex + 1 )
171  {
172  return;
173  }
174 
175 
176  if ( mPoints[geometryIndex].size() > 0 )
177  {
178  // negative index removes from end, eg -1 removes last one
179  if ( index < 0 )
180  {
181  index = mPoints[geometryIndex].size() + index;
182  }
183  mPoints[geometryIndex].removeAt( index );
184  }
185 
186  if ( doUpdate )
187  {
188  updateRect();
189  update();
190  }
191 }
192 
193 void QgsRubberBand::removeLastPoint( int geometryIndex, bool doUpdate/* = true*/ )
194 {
195  removePoint( -1, doUpdate, geometryIndex );
196 }
197 
201 void QgsRubberBand::movePoint( const QgsPoint & p, int geometryIndex )
202 {
203  if ( mPoints.size() < geometryIndex + 1 )
204  {
205  return;
206  }
207 
208  if ( mPoints.at( geometryIndex ).size() < 1 )
209  {
210  return;
211  }
212 
213  mPoints[geometryIndex].last() = p;
214 
215  updateRect();
216  update();
217 }
218 
219 void QgsRubberBand::movePoint( int index, const QgsPoint& p, int geometryIndex )
220 {
221  if ( mPoints.size() < geometryIndex + 1 )
222  {
223  return;
224  }
225 
226  if ( mPoints.at( geometryIndex ).size() < index )
227  {
228  return;
229  }
230 
231  mPoints[geometryIndex][index] = p;
232 
233  updateRect();
234  update();
235 }
236 
238 {
239  if ( !geom )
240  {
241  reset( mGeometryType );
242  return;
243  }
244 
245  reset( geom->type() );
246  addGeometry( geom, layer );
247 }
248 
250 {
251  if ( !geom )
252  {
253  return;
254  }
255 
256  //maprender object of canvas
257  const QgsMapSettings& ms = mMapCanvas->mapSettings();
258 
259  int idx = mPoints.size();
260 
261  switch ( geom->wkbType() )
262  {
263 
264  case QGis::WKBPoint:
265  case QGis::WKBPoint25D:
266  {
267  QgsPoint pt;
268  if ( layer )
269  {
270  pt = ms.layerToMapCoordinates( layer, geom->asPoint() );
271  }
272  else
273  {
274  pt = geom->asPoint();
275  }
276  addPoint( pt, false, idx );
277  removeLastPoint( idx , false );
278  }
279  break;
280 
281  case QGis::WKBMultiPoint:
283  {
284  QgsMultiPoint mpt = geom->asMultiPoint();
285  for ( int i = 0; i < mpt.size(); ++i, ++idx )
286  {
287  QgsPoint pt = mpt[i];
288  if ( layer )
289  {
290  addPoint( ms.layerToMapCoordinates( layer, pt ), false, idx );
291  removeLastPoint( idx , false );
292  }
293  else
294  {
295  addPoint( pt, false, idx );
296  removeLastPoint( idx , false );
297  }
298  }
299  }
300  break;
301 
302  case QGis::WKBLineString:
304  {
305  QgsPolyline line = geom->asPolyline();
306  for ( int i = 0; i < line.count(); i++ )
307  {
308  if ( layer )
309  {
310  addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx );
311  }
312  else
313  {
314  addPoint( line[i], false, idx );
315  }
316  }
317  }
318  break;
319 
322  {
323 
324  QgsMultiPolyline mline = geom->asMultiPolyline();
325  for ( int i = 0; i < mline.size(); ++i, ++idx )
326  {
327  QgsPolyline line = mline[i];
328 
329  if ( line.size() == 0 )
330  {
331  --idx;
332  }
333 
334  for ( int j = 0; j < line.size(); ++j )
335  {
336  if ( layer )
337  {
338  addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx );
339  }
340  else
341  {
342  addPoint( line[j], false, idx );
343  }
344  }
345  }
346  }
347  break;
348 
349  case QGis::WKBPolygon:
350  case QGis::WKBPolygon25D:
351  {
352  QgsPolygon poly = geom->asPolygon();
353  QgsPolyline line = poly[0];
354  for ( int i = 0; i < line.count(); i++ )
355  {
356  if ( layer )
357  {
358  addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx );
359  }
360  else
361  {
362  addPoint( line[i], false, idx );
363  }
364  }
365  }
366  break;
367 
370  {
371 
372  QgsMultiPolygon multipoly = geom->asMultiPolygon();
373  for ( int i = 0; i < multipoly.size(); ++i, ++idx )
374  {
375  QgsPolygon poly = multipoly[i];
376  QgsPolyline line = poly[0];
377  for ( int j = 0; j < line.count(); ++j )
378  {
379  if ( layer )
380  {
381  addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx );
382  }
383  else
384  {
385  addPoint( line[j], false, idx );
386  }
387  }
388  }
389  }
390  break;
391 
392  case QGis::WKBUnknown:
393  default:
394  return;
395  }
396 
397  updateRect();
398  update();
399 }
400 
401 void QgsRubberBand::setToCanvasRectangle( const QRect& rect )
402 {
403  if ( !mMapCanvas )
404  {
405  return;
406  }
407 
408  const QgsMapToPixel* transform = mMapCanvas->getCoordinateTransform();
409  QgsPoint ll = transform->toMapCoordinates( rect.left(), rect.bottom() );
410  QgsPoint ur = transform->toMapCoordinates( rect.right(), rect.top() );
411 
412  reset( QGis::Polygon );
413  addPoint( ll, false );
414  addPoint( QgsPoint( ur.x(), ll.y() ), false );
415  addPoint( ur, false );
416  addPoint( QgsPoint( ll.x(), ur.y() ), true );
417 }
418 
422 void QgsRubberBand::paint( QPainter* p )
423 {
424  if ( mPoints.size() > 0 )
425  {
426  p->setBrush( mBrush );
427  p->setPen( mPen );
428 
429  Q_FOREACH( const QList<QgsPoint>& line, mPoints )
430  {
431  QVector<QPointF> pts;
432  Q_FOREACH( const QgsPoint& pt, line )
433  {
434  const QPointF cur = toCanvasCoordinates( QgsPoint( pt.x() + mTranslationOffsetX, pt.y() + mTranslationOffsetY ) ) - pos();
435  if ( pts.empty() || std::abs( pts.back().x() - cur.x() ) > 1 || std::abs( pts.back().y() - cur.y() ) > 1 )
436  pts.append( cur );
437  }
438 
439  switch ( mGeometryType )
440  {
441  case QGis::Polygon:
442  {
443  p->drawPolygon( pts );
444  }
445  break;
446 
447  case QGis::Point:
448  {
449  Q_FOREACH( const QPointF& pt, pts )
450  {
451  double x = pt.x();
452  double y = pt.y();
453 
454  qreal s = ( mIconSize - 1 ) / 2;
455 
456  switch ( mIconType )
457  {
458  case ICON_NONE:
459  break;
460 
461  case ICON_CROSS:
462  p->drawLine( QLineF( x - s, y, x + s, y ) );
463  p->drawLine( QLineF( x, y - s, x, y + s ) );
464  break;
465 
466  case ICON_X:
467  p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
468  p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
469  break;
470 
471  case ICON_BOX:
472  p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
473  p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
474  p->drawLine( QLineF( x + s, y + s, x - s, y + s ) );
475  p->drawLine( QLineF( x - s, y + s, x - s, y - s ) );
476  break;
477 
478  case ICON_FULL_BOX:
479  p->drawRect( x - s, y - s, mIconSize, mIconSize );
480  break;
481 
482  case ICON_CIRCLE:
483  p->drawEllipse( x - s, y - s, mIconSize, mIconSize );
484  break;
485  }
486  }
487  }
488  break;
489 
490  case QGis::Line:
491  default:
492  {
493  p->drawPolyline( pts );
494  }
495  break;
496  }
497  }
498  }
499 }
500 
502 {
503  if ( mPoints.size() > 0 )
504  {
505  //initial point
506  QList<QgsPoint>::const_iterator it = mPoints.at( 0 ).constBegin();
507  if ( it == mPoints.at( 0 ).constEnd() )
508  {
509  return;
510  }
511 
512  qreal scale = mMapCanvas->mapUnitsPerPixel();
513  qreal s = ( mIconSize - 1 ) / 2 * scale;
514  qreal p = mPen.width() * scale;
515 
516  QgsRectangle r( it->x() + mTranslationOffsetX - s - p, it->y() + mTranslationOffsetY - s - p,
517  it->x() + mTranslationOffsetX + s + p, it->y() + mTranslationOffsetY + s + p );
518 
519  for ( int i = 0; i < mPoints.size(); ++i )
520  {
521  QList<QgsPoint>::const_iterator it = mPoints.at( i ).constBegin();
522  for ( ; it != mPoints.at( i ).constEnd(); ++it )
523  {
524  QgsRectangle rect = QgsRectangle( it->x() + mTranslationOffsetX - s - p, it->y() + mTranslationOffsetY - s - p,
525  it->x() + mTranslationOffsetX + s + p, it->y() + mTranslationOffsetY + s + p );
526  r.combineExtentWith( &rect );
527  }
528  }
529  setRect( r );
530  }
531  else
532  {
533  setRect( QgsRectangle() );
534  }
535  setVisible( mPoints.size() > 0 );
536 }
537 
538 void QgsRubberBand::setTranslationOffset( double dx, double dy )
539 {
540  mTranslationOffsetX = dx;
541  mTranslationOffsetY = dy;
542  updateRect();
543 }
544 
546 {
547  return mPoints.size();
548 }
549 
550 int QgsRubberBand::partSize( int geometryIndex ) const
551 {
552  if ( geometryIndex < 0 || geometryIndex >= mPoints.size() ) return 0;
553  return mPoints[geometryIndex].size();
554 }
555 
557 {
558  int count = 0;
559  QList<QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
560  for ( ; it != mPoints.constEnd(); ++it )
561  {
562  QList<QgsPoint>::const_iterator iter = it->constBegin();
563  for ( ; iter != it->constEnd(); ++iter )
564  {
565  ++count;
566  }
567  }
568  return count;
569 }
570 
571 const QgsPoint *QgsRubberBand::getPoint( int i, int j ) const
572 {
573  if ( i < mPoints.size() && j < mPoints[i].size() )
574  return &mPoints[i][j];
575  else
576  return 0;
577 }
578 
580 {
581  QgsGeometry *geom = NULL;
582 
583  switch ( mGeometryType )
584  {
585  case QGis::Polygon:
586  {
587  QgsPolygon polygon;
588  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
589  for ( ; it != mPoints.constEnd(); ++it )
590  {
591  polygon.append( getPolyline( *it ) );
592  }
593  geom = QgsGeometry::fromPolygon( polygon );
594  break;
595  }
596 
597  case QGis::Point:
598  {
599  QgsMultiPoint multiPoint;
600 
601  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
602  for ( ; it != mPoints.constEnd(); ++it )
603  {
604  multiPoint += getPolyline( *it );
605  }
606  geom = QgsGeometry::fromMultiPoint( multiPoint );
607  break;
608  }
609 
610  case QGis::Line:
611  default:
612  {
613  if ( mPoints.size() > 0 )
614  {
615  if ( mPoints.size() > 1 )
616  {
617  QgsMultiPolyline multiPolyline;
618  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
619  for ( ; it != mPoints.constEnd(); ++it )
620  {
621  multiPolyline.append( getPolyline( *it ) );
622  }
623  geom = QgsGeometry::fromMultiPolyline( multiPolyline );
624  }
625  else
626  {
628  }
629  }
630  break;
631  }
632  }
633  return geom;
634 }
635 
636 QgsPolyline QgsRubberBand::getPolyline( const QList<QgsPoint> & points )
637 {
638  QgsPolyline polyline;
639  QList<QgsPoint>::const_iterator iter = points.constBegin();
640  for ( ; iter != points.constEnd(); ++iter )
641  {
642  polyline.append( *iter );
643  }
644  return polyline;
645 }
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
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:105
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 ...
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.)
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