QGIS API Documentation  2.2.0-Valmiera
 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
258  if ( !mr )
259  {
260  return;
261  }
262 
263  int idx = mPoints.size();
264 
265  switch ( geom->wkbType() )
266  {
267 
268  case QGis::WKBPoint:
269  case QGis::WKBPoint25D:
270  {
271  QgsPoint pt;
272  if ( layer )
273  {
274  pt = mr->layerToMapCoordinates( layer, geom->asPoint() );
275  }
276  else
277  {
278  pt = geom->asPoint();
279  }
280  addPoint( pt, false, idx );
281  removeLastPoint( idx , false );
282  }
283  break;
284 
285  case QGis::WKBMultiPoint:
287  {
288  QgsMultiPoint mpt = geom->asMultiPoint();
289  for ( int i = 0; i < mpt.size(); ++i, ++idx )
290  {
291  QgsPoint pt = mpt[i];
292  if ( layer )
293  {
294  addPoint( mr->layerToMapCoordinates( layer, pt ), false, idx );
295  removeLastPoint( idx , false );
296  }
297  else
298  {
299  addPoint( pt, false, idx );
300  removeLastPoint( idx , false );
301  }
302  }
303  }
304  break;
305 
306  case QGis::WKBLineString:
308  {
309  QgsPolyline line = geom->asPolyline();
310  for ( int i = 0; i < line.count(); i++ )
311  {
312  if ( layer )
313  {
314  addPoint( mr->layerToMapCoordinates( layer, line[i] ), false, idx );
315  }
316  else
317  {
318  addPoint( line[i], false, idx );
319  }
320  }
321  }
322  break;
323 
326  {
327 
328  QgsMultiPolyline mline = geom->asMultiPolyline();
329  for ( int i = 0; i < mline.size(); ++i, ++idx )
330  {
331  QgsPolyline line = mline[i];
332 
333  if ( line.size() == 0 )
334  {
335  --idx;
336  }
337 
338  for ( int j = 0; j < line.size(); ++j )
339  {
340  if ( layer )
341  {
342  addPoint( mr->layerToMapCoordinates( layer, line[j] ), false, idx );
343  }
344  else
345  {
346  addPoint( line[j], false, idx );
347  }
348  }
349  }
350  }
351  break;
352 
353  case QGis::WKBPolygon:
354  case QGis::WKBPolygon25D:
355  {
356  QgsPolygon poly = geom->asPolygon();
357  QgsPolyline line = poly[0];
358  for ( int i = 0; i < line.count(); i++ )
359  {
360  if ( layer )
361  {
362  addPoint( mr->layerToMapCoordinates( layer, line[i] ), false, idx );
363  }
364  else
365  {
366  addPoint( line[i], false, idx );
367  }
368  }
369  }
370  break;
371 
374  {
375 
376  QgsMultiPolygon multipoly = geom->asMultiPolygon();
377  for ( int i = 0; i < multipoly.size(); ++i, ++idx )
378  {
379  QgsPolygon poly = multipoly[i];
380  QgsPolyline line = poly[0];
381  for ( int j = 0; j < line.count(); ++j )
382  {
383  if ( layer )
384  {
385  addPoint( mr->layerToMapCoordinates( layer, line[j] ), false, idx );
386  }
387  else
388  {
389  addPoint( line[j], false, idx );
390  }
391  }
392  }
393  }
394  break;
395 
396  case QGis::WKBUnknown:
397  default:
398  return;
399  }
400 
401  updateRect();
402  update();
403 }
404 
405 void QgsRubberBand::setToCanvasRectangle( const QRect& rect )
406 {
407  if ( !mMapCanvas )
408  {
409  return;
410  }
411 
412  const QgsMapToPixel* transform = mMapCanvas->getCoordinateTransform();
413  QgsPoint ll = transform->toMapCoordinates( rect.left(), rect.bottom() );
414  QgsPoint ur = transform->toMapCoordinates( rect.right(), rect.top() );
415 
416  reset( QGis::Polygon );
417  addPoint( ll, false );
418  addPoint( QgsPoint( ur.x(), ll.y() ), false );
419  addPoint( ur, false );
420  addPoint( QgsPoint( ll.x(), ur.y() ), true );
421 }
422 
426 void QgsRubberBand::paint( QPainter* p )
427 {
428  if ( mPoints.size() > 0 )
429  {
430  p->setBrush( mBrush );
431  p->setPen( mPen );
432 
433  Q_FOREACH( const QList<QgsPoint>& line, mPoints )
434  {
435  QVector<QPointF> pts;
436  Q_FOREACH( const QgsPoint& pt, line )
437  {
438  const QPointF cur = toCanvasCoordinates( QgsPoint( pt.x() + mTranslationOffsetX, pt.y() + mTranslationOffsetY ) ) - pos();
439  if ( pts.empty() || std::abs( pts.back().x() - cur.x() ) > 1 || std::abs( pts.back().y() - cur.y() ) > 1 )
440  pts.append( cur );
441  }
442 
443  switch ( mGeometryType )
444  {
445  case QGis::Polygon:
446  {
447  p->drawPolygon( pts );
448  }
449  break;
450 
451  case QGis::Point:
452  {
453  Q_FOREACH( const QPointF& pt, pts )
454  {
455  double x = pt.x();
456  double y = pt.y();
457 
458  qreal s = ( mIconSize - 1 ) / 2;
459 
460  switch ( mIconType )
461  {
462  case ICON_NONE:
463  break;
464 
465  case ICON_CROSS:
466  p->drawLine( QLineF( x - s, y, x + s, y ) );
467  p->drawLine( QLineF( x, y - s, x, y + s ) );
468  break;
469 
470  case ICON_X:
471  p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
472  p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
473  break;
474 
475  case ICON_BOX:
476  p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
477  p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
478  p->drawLine( QLineF( x + s, y + s, x - s, y + s ) );
479  p->drawLine( QLineF( x - s, y + s, x - s, y - s ) );
480  break;
481 
482  case ICON_FULL_BOX:
483  p->drawRect( x - s, y - s, mIconSize, mIconSize );
484  break;
485 
486  case ICON_CIRCLE:
487  p->drawEllipse( x - s, y - s, mIconSize, mIconSize );
488  break;
489  }
490  }
491  }
492  break;
493 
494  case QGis::Line:
495  default:
496  {
497  p->drawPolyline( pts );
498  }
499  break;
500  }
501  }
502  }
503 }
504 
506 {
507  if ( mPoints.size() > 0 )
508  {
509  //initial point
510  QList<QgsPoint>::const_iterator it = mPoints.at( 0 ).constBegin();
511  if ( it == mPoints.at( 0 ).constEnd() )
512  {
513  return;
514  }
515 
516  qreal scale = mMapCanvas->mapUnitsPerPixel();
517  qreal s = ( mIconSize - 1 ) / 2 * scale;
518  qreal p = mPen.width() * scale;
519 
520  QgsRectangle r( it->x() + mTranslationOffsetX - s - p, it->y() + mTranslationOffsetY - s - p,
521  it->x() + mTranslationOffsetX + s + p, it->y() + mTranslationOffsetY + s + p );
522 
523  for ( int i = 0; i < mPoints.size(); ++i )
524  {
525  QList<QgsPoint>::const_iterator it = mPoints.at( i ).constBegin();
526  for ( ; it != mPoints.at( i ).constEnd(); ++it )
527  {
528  QgsRectangle rect = QgsRectangle( it->x() + mTranslationOffsetX - s - p, it->y() + mTranslationOffsetY - s - p,
529  it->x() + mTranslationOffsetX + s + p, it->y() + mTranslationOffsetY + s + p );
530  r.combineExtentWith( &rect );
531  }
532  }
533  setRect( r );
534  }
535  else
536  {
537  setRect( QgsRectangle() );
538  }
539  setVisible( mPoints.size() > 0 );
540 }
541 
542 void QgsRubberBand::setTranslationOffset( double dx, double dy )
543 {
544  mTranslationOffsetX = dx;
545  mTranslationOffsetY = dy;
546  updateRect();
547 }
548 
550 {
551  return mPoints.size();
552 }
553 
554 int QgsRubberBand::partSize( int geometryIndex ) const
555 {
556  if ( geometryIndex < 0 || geometryIndex >= mPoints.size() ) return 0;
557  return mPoints[geometryIndex].size();
558 }
559 
561 {
562  int count = 0;
563  QList<QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
564  for ( ; it != mPoints.constEnd(); ++it )
565  {
566  QList<QgsPoint>::const_iterator iter = it->constBegin();
567  for ( ; iter != it->constEnd(); ++iter )
568  {
569  ++count;
570  }
571  }
572  return count;
573 }
574 
575 const QgsPoint *QgsRubberBand::getPoint( int i, int j ) const
576 {
577  if ( i < mPoints.size() && j < mPoints[i].size() )
578  return &mPoints[i][j];
579  else
580  return 0;
581 }
582 
584 {
585  QgsGeometry *geom = NULL;
586 
587  switch ( mGeometryType )
588  {
589  case QGis::Polygon:
590  {
591  QgsPolygon polygon;
592  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
593  for ( ; it != mPoints.constEnd(); ++it )
594  {
595  polygon.append( getPolyline( *it ) );
596  }
597  geom = QgsGeometry::fromPolygon( polygon );
598  break;
599  }
600 
601  case QGis::Point:
602  {
603  QgsMultiPoint multiPoint;
604 
605  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
606  for ( ; it != mPoints.constEnd(); ++it )
607  {
608  multiPoint += getPolyline( *it );
609  }
610  geom = QgsGeometry::fromMultiPoint( multiPoint );
611  break;
612  }
613 
614  case QGis::Line:
615  default:
616  {
617  if ( mPoints.size() > 0 )
618  {
619  if ( mPoints.size() > 1 )
620  {
621  QgsMultiPolyline multiPolyline;
622  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
623  for ( ; it != mPoints.constEnd(); ++it )
624  {
625  multiPolyline.append( getPolyline( *it ) );
626  }
627  geom = QgsGeometry::fromMultiPolyline( multiPolyline );
628  }
629  else
630  {
632  }
633  }
634  break;
635  }
636  }
637  return geom;
638 }
639 
640 QgsPolyline QgsRubberBand::getPolyline( const QList<QgsPoint> & points )
641 {
642  QgsPolyline polyline;
643  QList<QgsPoint>::const_iterator iter = points.constBegin();
644  for ( ; iter != points.constEnd(); ++iter )
645  {
646  polyline.append( *iter );
647  }
648  return polyline;
649 }