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