QGIS API Documentation  master-3f58142
src/gui/qgsrubberband.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsrubberband.cpp - Rubberband widget for drawing multilines and polygons
00003      --------------------------------------
00004     Date                 : 07-Jan-2006
00005     Copyright            : (C) 2006 by Tom Elwertowski
00006     Email                : telwertowski at users dot sourceforge dot net
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 #include "qgsrubberband.h"
00017 #include "qgsfeature.h"
00018 #include "qgsgeometry.h"
00019 #include "qgslogger.h"
00020 #include "qgsmapcanvas.h"
00021 #include "qgsmaprenderer.h"
00022 #include "qgsvectorlayer.h"
00023 #include <QPainter>
00024 
00030 QgsRubberBand::QgsRubberBand( QgsMapCanvas* mapCanvas, QGis::GeometryType geometryType )
00031     : QgsMapCanvasItem( mapCanvas )
00032     , mWidth( 1 )
00033     , mIconSize( 5 )
00034     , mIconType( ICON_CIRCLE )
00035     , mGeometryType( geometryType )
00036     , mTranslationOffsetX( 0.0 )
00037     , mTranslationOffsetY( 0.0 )
00038 {
00039   reset( geometryType );
00040   setColor( QColor( Qt::lightGray ) );
00041 }
00042 
00043 QgsRubberBand::QgsRubberBand( QgsMapCanvas* mapCanvas, bool isPolygon )
00044     : QgsMapCanvasItem( mapCanvas )
00045     , mWidth( 1 )
00046     , mIconSize( 5 )
00047     , mIconType( ICON_CIRCLE )
00048     , mTranslationOffsetX( 0.0 )
00049     , mTranslationOffsetY( 0.0 )
00050 {
00051   reset( isPolygon ? QGis::Polygon : QGis::Line );
00052   setColor( QColor( Qt::lightGray ) );
00053 }
00054 
00055 QgsRubberBand::QgsRubberBand(): QgsMapCanvasItem( 0 )
00056 {
00057 }
00058 
00059 QgsRubberBand::~QgsRubberBand()
00060 {
00061 }
00062 
00066 void QgsRubberBand::setColor( const QColor & color )
00067 {
00068   mPen.setColor( color );
00069   QColor fillColor( color.red(), color.green(), color.blue(), 63 );
00070   mBrush.setColor( fillColor );
00071   mBrush.setStyle( Qt::SolidPattern );
00072 }
00073 
00077 void QgsRubberBand::setWidth( int width )
00078 {
00079   mWidth = width;
00080 }
00081 
00082 void QgsRubberBand::setIcon( IconType icon )
00083 {
00084   mIconType = icon;
00085 }
00086 
00087 void QgsRubberBand::setIconSize( int iconSize )
00088 {
00089   mIconSize = iconSize;
00090 }
00091 
00095 void QgsRubberBand::reset( QGis::GeometryType geometryType )
00096 {
00097   mPoints.clear();
00098   mGeometryType = geometryType;
00099   updateRect();
00100   update();
00101 }
00102 
00103 void QgsRubberBand::reset( bool isPolygon )
00104 {
00105   mPoints.clear();
00106   mGeometryType = isPolygon ? QGis::Polygon : QGis::Line;
00107   updateRect();
00108   update();
00109 }
00110 
00114 void QgsRubberBand::addPoint( const QgsPoint & p, bool doUpdate /* = true */, int geometryIndex )
00115 {
00116   if ( geometryIndex < 0 )
00117   {
00118     geometryIndex = mPoints.size() - 1;
00119   }
00120 
00121   if ( geometryIndex < 0 || geometryIndex > mPoints.size() )
00122   {
00123     return;
00124   }
00125 
00126   if ( geometryIndex == mPoints.size() )
00127   {
00128     mPoints.push_back( QList<QgsPoint>() << p );
00129   }
00130 
00131   if ( mPoints[geometryIndex].size() == 2 &&
00132        mPoints[geometryIndex][0] == mPoints[geometryIndex][1] )
00133   {
00134     mPoints[geometryIndex].last() = p;
00135   }
00136   else
00137   {
00138     mPoints[geometryIndex] << p;
00139   }
00140 
00141 
00142   if ( doUpdate )
00143   {
00144     updateRect();
00145     update();
00146   }
00147 }
00148 
00149 
00150 void QgsRubberBand::removePoint( int index, bool doUpdate/* = true*/, int geometryIndex/* = 0*/ )
00151 {
00152 
00153   if ( mPoints.size() < geometryIndex + 1 )
00154   {
00155     return;
00156   }
00157 
00158 
00159   if ( mPoints[geometryIndex].size() > 0 )
00160   {
00161     // negative index removes from end, eg -1 removes last one
00162     if ( index < 0 )
00163     {
00164       index = mPoints[geometryIndex].size() + index;
00165     }
00166     mPoints[geometryIndex].removeAt( index );
00167   }
00168 
00169   if ( doUpdate )
00170   {
00171     updateRect();
00172     update();
00173   }
00174 }
00175 
00176 void QgsRubberBand::removeLastPoint( int geometryIndex )
00177 {
00178   removePoint( -1, true, geometryIndex );
00179 }
00180 
00184 void QgsRubberBand::movePoint( const QgsPoint & p, int geometryIndex )
00185 {
00186   if ( mPoints.size() < geometryIndex + 1 )
00187   {
00188     return;
00189   }
00190 
00191   if ( mPoints.at( geometryIndex ).size() < 1 )
00192   {
00193     return;
00194   }
00195 
00196   mPoints[geometryIndex].last() = p;
00197 
00198   updateRect();
00199   update();
00200 }
00201 
00202 void QgsRubberBand::movePoint( int index, const QgsPoint& p, int geometryIndex )
00203 {
00204   if ( mPoints.size() < geometryIndex + 1 )
00205   {
00206     return;
00207   }
00208 
00209   if ( mPoints.at( geometryIndex ).size() < index )
00210   {
00211     return;
00212   }
00213 
00214   mPoints[geometryIndex][index] = p;
00215 
00216   updateRect();
00217   update();
00218 }
00219 
00220 void QgsRubberBand::setToGeometry( QgsGeometry* geom, QgsVectorLayer* layer )
00221 {
00222   reset( geom->type() );
00223   addGeometry( geom, layer );
00224 }
00225 
00226 void QgsRubberBand::addGeometry( QgsGeometry* geom, QgsVectorLayer* layer )
00227 {
00228   if ( !geom )
00229   {
00230     return;
00231   }
00232 
00233   //maprender object of canvas
00234   QgsMapRenderer* mr = mMapCanvas->mapRenderer();
00235   if ( !mr )
00236   {
00237     return;
00238   }
00239 
00240   int idx = mPoints.size();
00241 
00242   switch ( geom->wkbType() )
00243   {
00244 
00245     case QGis::WKBPoint:
00246     case QGis::WKBPoint25D:
00247     {
00248       QgsPoint pt;
00249       if ( layer )
00250       {
00251         pt = mr->layerToMapCoordinates( layer, geom->asPoint() );
00252       }
00253       else
00254       {
00255         pt = geom->asPoint();
00256       }
00257       addPoint( pt, false, idx );
00258     }
00259     break;
00260 
00261     case QGis::WKBMultiPoint:
00262     case QGis::WKBMultiPoint25D:
00263     {
00264       QgsMultiPoint mpt = geom->asMultiPoint();
00265       for ( int i = 0; i < mpt.size(); ++i, ++idx )
00266       {
00267         QgsPoint pt = mpt[i];
00268         if ( layer )
00269         {
00270           addPoint( mr->layerToMapCoordinates( layer, pt ), false, idx );
00271         }
00272         else
00273         {
00274           addPoint( pt, false, idx );
00275         }
00276       }
00277     }
00278     break;
00279 
00280     case QGis::WKBLineString:
00281     case QGis::WKBLineString25D:
00282     {
00283       QgsPolyline line = geom->asPolyline();
00284       for ( int i = 0; i < line.count(); i++ )
00285       {
00286         if ( layer )
00287         {
00288           addPoint( mr->layerToMapCoordinates( layer, line[i] ), false, idx );
00289         }
00290         else
00291         {
00292           addPoint( line[i], false, idx );
00293         }
00294       }
00295     }
00296     break;
00297 
00298     case QGis::WKBMultiLineString:
00299     case QGis::WKBMultiLineString25D:
00300     {
00301 
00302       QgsMultiPolyline mline = geom->asMultiPolyline();
00303       for ( int i = 0; i < mline.size(); ++i, ++idx )
00304       {
00305         QgsPolyline line = mline[i];
00306 
00307         if ( line.size() == 0 )
00308         {
00309           --idx;
00310         }
00311 
00312         for ( int j = 0; j < line.size(); ++j )
00313         {
00314           if ( layer )
00315           {
00316             addPoint( mr->layerToMapCoordinates( layer, line[j] ), false, idx );
00317           }
00318           else
00319           {
00320             addPoint( line[j], false, idx );
00321           }
00322         }
00323       }
00324     }
00325     break;
00326 
00327     case QGis::WKBPolygon:
00328     case QGis::WKBPolygon25D:
00329     {
00330       QgsPolygon poly = geom->asPolygon();
00331       QgsPolyline line = poly[0];
00332       for ( int i = 0; i < line.count(); i++ )
00333       {
00334         if ( layer )
00335         {
00336           addPoint( mr->layerToMapCoordinates( layer, line[i] ), false, idx );
00337         }
00338         else
00339         {
00340           addPoint( line[i], false, idx );
00341         }
00342       }
00343     }
00344     break;
00345 
00346     case QGis::WKBMultiPolygon:
00347     case QGis::WKBMultiPolygon25D:
00348     {
00349 
00350       QgsMultiPolygon multipoly = geom->asMultiPolygon();
00351       for ( int i = 0; i < multipoly.size(); ++i, ++idx )
00352       {
00353         QgsPolygon poly = multipoly[i];
00354         QgsPolyline line = poly[0];
00355         for ( int j = 0; j < line.count(); ++j )
00356         {
00357           if ( layer )
00358           {
00359             addPoint( mr->layerToMapCoordinates( layer, line[j] ), false, idx );
00360           }
00361           else
00362           {
00363             addPoint( line[j], false, idx );
00364           }
00365         }
00366       }
00367     }
00368     break;
00369 
00370     case QGis::WKBUnknown:
00371     default:
00372       return;
00373   }
00374 
00375   updateRect();
00376   update();
00377 }
00378 
00379 void QgsRubberBand::setToCanvasRectangle( const QRect& rect )
00380 {
00381   if ( !mMapCanvas )
00382   {
00383     return;
00384   }
00385 
00386   const QgsMapToPixel* transform = mMapCanvas->getCoordinateTransform();
00387   QgsPoint ll = transform->toMapCoordinates( rect.left(), rect.bottom() );
00388   QgsPoint ur = transform->toMapCoordinates( rect.right(), rect.top() );
00389 
00390   reset( QGis::Polygon );
00391   addPoint( ll, false );
00392   addPoint( QgsPoint( ur.x(), ll.y() ), false );
00393   addPoint( ur, false );
00394   addPoint( QgsPoint( ll.x(), ur.y() ), true );
00395 }
00396 
00400 void QgsRubberBand::paint( QPainter* p )
00401 {
00402   QList<QgsPoint> currentList;
00403   if ( mPoints.size() > 0 )
00404   {
00405     p->setBrush( mBrush );
00406     mPen.setWidth( mWidth );
00407     p->setPen( mPen );
00408 
00409     for ( int i = 0; i < mPoints.size(); ++i )
00410     {
00411       QVector<QPointF> pts;
00412       QList<QgsPoint>::const_iterator it = mPoints.at( i ).constBegin();
00413       for ( ; it != mPoints.at( i ).constEnd(); ++it )
00414       {
00415         pts.append( toCanvasCoordinates( QgsPoint( it->x() + mTranslationOffsetX, it->y() + mTranslationOffsetY ) ) - pos() );
00416       }
00417 
00418       switch ( mGeometryType )
00419       {
00420         case QGis::Polygon:
00421         {
00422           p->drawPolygon( pts );
00423         }
00424         break;
00425 
00426         case QGis::Point:
00427         {
00428           QVector<QPointF>::const_iterator ptIt = pts.constBegin();
00429           for ( ; ptIt != pts.constEnd(); ++ptIt )
00430           {
00431             double x = ( *ptIt ).x();
00432             double y = ( *ptIt ).y();
00433 
00434             qreal s = ( mIconSize - 1 ) / 2;
00435 
00436             switch ( mIconType )
00437             {
00438               case ICON_NONE:
00439                 break;
00440 
00441               case ICON_CROSS:
00442                 p->drawLine( QLineF( x - s, y, x + s, y ) );
00443                 p->drawLine( QLineF( x, y - s, x, y + s ) );
00444                 break;
00445 
00446               case ICON_X:
00447                 p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
00448                 p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
00449                 break;
00450 
00451               case ICON_BOX:
00452                 p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
00453                 p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
00454                 p->drawLine( QLineF( x + s, y + s, x - s, y + s ) );
00455                 p->drawLine( QLineF( x - s, y + s, x - s, y - s ) );
00456                 break;
00457 
00458               case ICON_CIRCLE:
00459                 p->drawEllipse( x - s, y - s, mIconSize, mIconSize );
00460                 break;
00461             }
00462           }
00463         }
00464         break;
00465 
00466         case QGis::Line:
00467         default:
00468         {
00469           p->drawPolyline( pts );
00470         }
00471         break;
00472       }
00473     }
00474   }
00475 }
00476 
00477 void QgsRubberBand::updateRect()
00478 {
00479   if ( mPoints.size() > 0 )
00480   {
00481     //initial point
00482     QList<QgsPoint>::const_iterator it = mPoints.at( 0 ).constBegin();
00483     if ( it == mPoints.at( 0 ).constEnd() )
00484     {
00485       return;
00486     }
00487     qreal s = ( mIconSize - 1 ) / 2;
00488     qreal p = mWidth;
00489 
00490     QgsRectangle r( it->x() + mTranslationOffsetX - s - p, it->y() + mTranslationOffsetY - s - p,
00491                     it->x() + mTranslationOffsetX + s + p, it->y() + mTranslationOffsetY + s + p );
00492 
00493     for ( int i = 0; i < mPoints.size(); ++i )
00494     {
00495       QList<QgsPoint>::const_iterator it = mPoints.at( i ).constBegin();
00496       for ( ; it != mPoints.at( i ).constEnd(); ++it )
00497       {
00498         QgsRectangle rect = QgsRectangle( it->x() + mTranslationOffsetX - s - p, it->y() + mTranslationOffsetY - s - p,
00499                                           it->x() + mTranslationOffsetX + s + p, it->y() + mTranslationOffsetY + s + p );
00500         r.combineExtentWith( &rect );
00501       }
00502     }
00503     setRect( r );
00504   }
00505   else
00506   {
00507     setRect( QgsRectangle() );
00508   }
00509   setVisible( mPoints.size() > 0 );
00510 }
00511 
00512 void QgsRubberBand::setTranslationOffset( double dx, double dy )
00513 {
00514   mTranslationOffsetX = dx;
00515   mTranslationOffsetY = dy;
00516   updateRect();
00517 }
00518 
00519 int QgsRubberBand::size() const
00520 {
00521   return mPoints.size();
00522 }
00523 
00524 int QgsRubberBand::numberOfVertices() const
00525 {
00526   int count = 0;
00527   QList<QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
00528   for ( ; it != mPoints.constEnd(); ++it )
00529   {
00530     QList<QgsPoint>::const_iterator iter = it->constBegin();
00531     for ( ; iter != it->constEnd(); ++iter )
00532     {
00533       ++count;
00534     }
00535   }
00536   return count;
00537 }
00538 
00539 const QgsPoint *QgsRubberBand::getPoint( int i, int j ) const
00540 {
00541   if ( i < mPoints.size() && j < mPoints[i].size() )
00542     return &mPoints[i][j];
00543   else
00544     return 0;
00545 }
00546 
00547 QgsGeometry *QgsRubberBand::asGeometry()
00548 {
00549   QgsGeometry *geom = NULL;
00550 
00551   switch ( mGeometryType )
00552   {
00553     case QGis::Polygon:
00554     {
00555       QgsPolygon polygon;
00556       QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
00557       for ( ; it != mPoints.constEnd(); ++it )
00558       {
00559         polygon.append( getPolyline( *it ) );
00560       }
00561       geom = QgsGeometry::fromPolygon( polygon );
00562       break;
00563     }
00564 
00565     case QGis::Point:
00566     {
00567       QgsMultiPoint multiPoint;
00568 
00569       QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
00570       for ( ; it != mPoints.constEnd(); ++it )
00571       {
00572         multiPoint += getPolyline( *it );
00573       }
00574       geom = QgsGeometry::fromMultiPoint( multiPoint );
00575       break;
00576     }
00577 
00578     case QGis::Line:
00579     default:
00580     {
00581       if ( mPoints.size() > 0 )
00582       {
00583         if ( mPoints.size() > 1 )
00584         {
00585           QgsMultiPolyline multiPolyline;
00586           QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
00587           for ( ; it != mPoints.constEnd(); ++it )
00588           {
00589             multiPolyline.append( getPolyline( *it ) );
00590           }
00591           geom = QgsGeometry::fromMultiPolyline( multiPolyline );
00592         }
00593         else
00594         {
00595           geom = QgsGeometry::fromPolyline( getPolyline( mPoints[0] ) );
00596         }
00597       }
00598       break;
00599     }
00600   }
00601   return geom;
00602 }
00603 
00604 QgsPolyline QgsRubberBand::getPolyline( const QList<QgsPoint> & points )
00605 {
00606   QgsPolyline polyline;
00607   QList<QgsPoint>::const_iterator iter = points.constBegin();
00608   for ( ; iter != points.constEnd(); ++iter )
00609   {
00610     polyline.append( *iter );
00611   }
00612   return polyline;
00613 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines