QGIS API Documentation  2.4.0-Chugiak
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
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
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
A box is used to highlight points (□)
Definition: qgsrubberband.h:55
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: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.)
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.
A cross is used to highlight points (x)
Definition: qgsrubberband.h:51
static QgsPolyline getPolyline(const QList< QgsPoint > &points)
IconType mIconType
Icon to be shown.
A class to represent a point geometry.
Definition: qgspoint.h:63
A full box is used to highlight points (■)
Definition: qgsrubberband.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 ...
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
A cross is used to highlight points (+)
Definition: qgsrubberband.h:47
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
No icon is used.
Definition: qgsrubberband.h:43
IconType
Icons Added in 1.9.
Definition: qgsrubberband.h:38
void setColor(const QColor &color)
Set the color for the rubberband.
double mTranslationOffsetX
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.
void updateRect()
recalculates needed rectangle