Quantum GIS API Documentation  1.7.4
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 /* $Id$ */
00016 
00017 #include "qgsrubberband.h"
00018 #include "qgsfeature.h"
00019 #include "qgsgeometry.h"
00020 #include "qgslogger.h"
00021 #include "qgsmapcanvas.h"
00022 #include "qgsmaprenderer.h"
00023 #include "qgsvectorlayer.h"
00024 #include <QPainter>
00025 
00031 QgsRubberBand::QgsRubberBand( QgsMapCanvas* mapCanvas, bool isPolygon )
00032     : QgsMapCanvasItem( mapCanvas )
00033     , mIsPolygon( isPolygon )
00034     , mTranslationOffsetX( 0.0 )
00035     , mTranslationOffsetY( 0.0 )
00036 {
00037   reset( isPolygon );
00038   setColor( QColor( Qt::lightGray ) );
00039 }
00040 
00041 QgsRubberBand::QgsRubberBand(): QgsMapCanvasItem( 0 )
00042 {
00043 }
00044 
00045 QgsRubberBand::~QgsRubberBand()
00046 {
00047 }
00048 
00052 void QgsRubberBand::setColor( const QColor & color )
00053 {
00054   mPen.setColor( color );
00055   QColor fillColor( color.red(), color.green(), color.blue(), 63 );
00056   mBrush.setColor( fillColor );
00057   mBrush.setStyle( Qt::SolidPattern );
00058 }
00059 
00063 void QgsRubberBand::setWidth( int width )
00064 {
00065   mPen.setWidth( width );
00066 }
00067 
00071 void QgsRubberBand::reset( bool isPolygon )
00072 {
00073   mPoints.clear();
00074   mIsPolygon = isPolygon;
00075   updateRect();
00076   update();
00077 }
00078 
00082 void QgsRubberBand::addPoint( const QgsPoint & p, bool do_update /* = true */, int geometryIndex )
00083 {
00084   if ( geometryIndex < 0 )
00085   {
00086     geometryIndex = mPoints.size() - 1;
00087   }
00088 
00089   if ( geometryIndex < 0 || geometryIndex > mPoints.size() )
00090   {
00091     return;
00092   }
00093 
00094   if ( geometryIndex == mPoints.size() )
00095   {
00096     mPoints.push_back( QList<QgsPoint>() << p );
00097   }
00098 
00099   if ( mPoints[geometryIndex].size() == 2 &&
00100        mPoints[geometryIndex][0] == mPoints[geometryIndex][1] )
00101   {
00102     mPoints[geometryIndex].last() = p;
00103   }
00104   else
00105   {
00106     mPoints[geometryIndex] << p;
00107   }
00108 
00109 
00110   if ( do_update )
00111   {
00112     updateRect();
00113     update();
00114   }
00115 }
00116 
00117 void QgsRubberBand::removeLastPoint( int geometryIndex )
00118 {
00119   if ( mPoints.size() < geometryIndex + 1 )
00120   {
00121     return;
00122   }
00123 
00124   if ( mPoints[geometryIndex].size() > 0 )
00125   {
00126     mPoints[geometryIndex].pop_back();
00127   }
00128 
00129   updateRect();
00130   update();
00131 }
00132 
00136 void QgsRubberBand::movePoint( const QgsPoint & p, int geometryIndex )
00137 {
00138   if ( mPoints.size() < geometryIndex + 1 )
00139   {
00140     return;
00141   }
00142 
00143   if ( mPoints.at( geometryIndex ).size() < 1 )
00144   {
00145     return;
00146   }
00147 
00148   mPoints[geometryIndex].last() = p;
00149 
00150   updateRect();
00151   update();
00152 }
00153 
00154 void QgsRubberBand::movePoint( int index, const QgsPoint& p, int geometryIndex )
00155 {
00156   if ( mPoints.size() < geometryIndex + 1 )
00157   {
00158     return;
00159   }
00160 
00161   if ( mPoints.at( geometryIndex ).size() < index )
00162   {
00163     return;
00164   }
00165 
00166   mPoints[geometryIndex][index] = p;
00167 
00168   updateRect();
00169   update();
00170 }
00171 
00172 void QgsRubberBand::setToGeometry( QgsGeometry* geom, QgsVectorLayer* layer )
00173 {
00174   reset( mIsPolygon );
00175   addGeometry( geom, layer );
00176 }
00177 
00178 void QgsRubberBand::addGeometry( QgsGeometry* geom, QgsVectorLayer* layer )
00179 {
00180   if ( !geom )
00181   {
00182     return;
00183   }
00184 
00185   //maprender object of canvas
00186   QgsMapRenderer* mr = mMapCanvas->mapRenderer();
00187   if ( !mr )
00188   {
00189     return;
00190   }
00191 
00192   int idx = mPoints.size();
00193 
00194   switch ( geom->wkbType() )
00195   {
00196 
00197     case QGis::WKBPoint:
00198     case QGis::WKBPoint25D:
00199     {
00200       mIsPolygon = true;
00201       double d = mMapCanvas->extent().width() * 0.005;
00202       QgsPoint pt;
00203       if ( layer )
00204       {
00205         pt = mr->layerToMapCoordinates( layer, geom->asPoint() );
00206       }
00207       else
00208       {
00209         pt = geom->asPoint();
00210       }
00211       addPoint( QgsPoint( pt.x() - d, pt.y() - d ), false, idx );
00212       addPoint( QgsPoint( pt.x() + d, pt.y() - d ), false, idx );
00213       addPoint( QgsPoint( pt.x() + d, pt.y() + d ), false, idx );
00214       addPoint( QgsPoint( pt.x() - d, pt.y() + d ), false, idx );
00215     }
00216     break;
00217 
00218     case QGis::WKBMultiPoint:
00219     case QGis::WKBMultiPoint25D:
00220     {
00221       mIsPolygon = true;
00222       double d = mMapCanvas->extent().width() * 0.005;
00223       QgsMultiPoint mpt = geom->asMultiPoint();
00224       for ( int i = 0; i < mpt.size(); ++i, ++idx )
00225       {
00226         QgsPoint pt = mpt[i];
00227         if ( layer )
00228         {
00229           addPoint( mr->layerToMapCoordinates( layer, QgsPoint( pt.x() - d, pt.y() - d ) ), false, idx );
00230           addPoint( mr->layerToMapCoordinates( layer, QgsPoint( pt.x() + d, pt.y() - d ) ), false, idx );
00231           addPoint( mr->layerToMapCoordinates( layer, QgsPoint( pt.x() + d, pt.y() + d ) ), false, idx );
00232           addPoint( mr->layerToMapCoordinates( layer, QgsPoint( pt.x() - d, pt.y() + d ) ), false, idx );
00233         }
00234         else
00235         {
00236           addPoint( QgsPoint( pt.x() - d, pt.y() - d ), false, idx );
00237           addPoint( QgsPoint( pt.x() + d, pt.y() - d ), false, idx );
00238           addPoint( QgsPoint( pt.x() + d, pt.y() + d ), false, idx );
00239           addPoint( QgsPoint( pt.x() - d, pt.y() + d ), false, idx );
00240         }
00241       }
00242     }
00243     break;
00244 
00245     case QGis::WKBLineString:
00246     case QGis::WKBLineString25D:
00247     {
00248       mIsPolygon = false;
00249       QgsPolyline line = geom->asPolyline();
00250       for ( int i = 0; i < line.count(); i++ )
00251       {
00252         if ( layer )
00253         {
00254           addPoint( mr->layerToMapCoordinates( layer, line[i] ), false, idx );
00255         }
00256         else
00257         {
00258           addPoint( line[i], false, idx );
00259         }
00260       }
00261     }
00262     break;
00263 
00264     case QGis::WKBMultiLineString:
00265     case QGis::WKBMultiLineString25D:
00266     {
00267       mIsPolygon = false;
00268       mPoints.clear();
00269 
00270       QgsMultiPolyline mline = geom->asMultiPolyline();
00271       for ( int i = 0; i < mline.size(); ++i, ++idx )
00272       {
00273         QgsPolyline line = mline[i];
00274         for ( int j = 0; j < line.size(); ++j )
00275         {
00276           if ( layer )
00277           {
00278             addPoint( mr->layerToMapCoordinates( layer, line[j] ), false, idx );
00279           }
00280           else
00281           {
00282             addPoint( line[j], false, idx );
00283           }
00284         }
00285       }
00286     }
00287     break;
00288 
00289     case QGis::WKBPolygon:
00290     case QGis::WKBPolygon25D:
00291     {
00292       mIsPolygon = true;
00293       QgsPolygon poly = geom->asPolygon();
00294       QgsPolyline line = poly[0];
00295       for ( int i = 0; i < line.count(); i++ )
00296       {
00297         if ( layer )
00298         {
00299           addPoint( mr->layerToMapCoordinates( layer, line[i] ), false, idx );
00300         }
00301         else
00302         {
00303           addPoint( line[i], false, idx );
00304         }
00305       }
00306     }
00307     break;
00308 
00309     case QGis::WKBMultiPolygon:
00310     case QGis::WKBMultiPolygon25D:
00311     {
00312       mIsPolygon = true;
00313       mPoints.clear();
00314 
00315       QgsMultiPolygon multipoly = geom->asMultiPolygon();
00316       for ( int i = 0; i < multipoly.size(); ++i, ++idx )
00317       {
00318         QgsPolygon poly = multipoly[i];
00319         QgsPolyline line = poly[0];
00320         for ( int j = 0; j < line.count(); ++j )
00321         {
00322           if ( layer )
00323           {
00324             addPoint( mr->layerToMapCoordinates( layer, line[j] ), false, idx );
00325           }
00326           else
00327           {
00328             addPoint( line[j], false, idx );
00329           }
00330         }
00331       }
00332     }
00333     break;
00334 
00335     case QGis::WKBUnknown:
00336     default:
00337       return;
00338   }
00339 
00340   updateRect();
00341   update();
00342 }
00343 
00344 void QgsRubberBand::setToCanvasRectangle( const QRect& rect )
00345 {
00346   if ( !mMapCanvas )
00347   {
00348     return;
00349   }
00350 
00351   const QgsMapToPixel* transform = mMapCanvas->getCoordinateTransform();
00352   QgsPoint ll = transform->toMapCoordinates( rect.left(), rect.bottom() );
00353   QgsPoint ur = transform->toMapCoordinates( rect.right(), rect.top() );
00354 
00355   reset( true );
00356   addPoint( ll, false );
00357   addPoint( QgsPoint( ur.x(), ll.y() ), false );
00358   addPoint( ur, false );
00359   addPoint( QgsPoint( ll.x(), ur.y() ), true );
00360 }
00361 
00365 void QgsRubberBand::paint( QPainter* p )
00366 {
00367   QList<QgsPoint> currentList;
00368   if ( mPoints.size() > 0 )
00369   {
00370     p->setPen( mPen );
00371     p->setBrush( mBrush );
00372 
00373     for ( int i = 0; i < mPoints.size(); ++i )
00374     {
00375       QPolygonF pts;
00376       QList<QgsPoint>::const_iterator it = mPoints.at( i ).constBegin();
00377       for ( ; it != mPoints.at( i ).constEnd(); ++it )
00378       {
00379         pts.append( toCanvasCoordinates( QgsPoint( it->x() + mTranslationOffsetX, it->y() + mTranslationOffsetY ) ) - pos() );
00380       }
00381 
00382       if ( mIsPolygon )
00383       {
00384         p->drawPolygon( pts );
00385       }
00386       else
00387       {
00388         p->drawPolyline( pts );
00389       }
00390     }
00391   }
00392 }
00393 
00394 void QgsRubberBand::updateRect()
00395 {
00396   if ( mPoints.size() > 0 )
00397   {
00398     //initial point
00399     QList<QgsPoint>::const_iterator it = mPoints.at( 0 ).constBegin();
00400     if ( it == mPoints.at( 0 ).constEnd() )
00401     {
00402       return;
00403     }
00404     QgsRectangle r( it->x() + mTranslationOffsetX, it->y() + mTranslationOffsetY,
00405                     it->x() + mTranslationOffsetX, it->y() + mTranslationOffsetY );
00406 
00407     for ( int i = 0; i < mPoints.size(); ++i )
00408     {
00409       QList<QgsPoint>::const_iterator it = mPoints.at( i ).constBegin();
00410       for ( ; it != mPoints.at( i ).constEnd(); ++it )
00411       {
00412         r.combineExtentWith( it->x() + mTranslationOffsetX, it->y() + mTranslationOffsetY );
00413       }
00414     }
00415     setRect( r );
00416   }
00417   else
00418   {
00419     setRect( QgsRectangle() );
00420   }
00421   setVisible( mPoints.size() > 0 );
00422 }
00423 
00424 void QgsRubberBand::setTranslationOffset( double dx, double dy )
00425 {
00426   mTranslationOffsetX = dx;
00427   mTranslationOffsetY = dy;
00428   updateRect();
00429 }
00430 
00431 int QgsRubberBand::size() const
00432 {
00433   return mPoints.size();
00434 }
00435 
00436 int QgsRubberBand::numberOfVertices() const
00437 {
00438   int count = 0;
00439   QList<QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
00440   for ( ; it != mPoints.constEnd(); ++it )
00441   {
00442     QList<QgsPoint>::const_iterator iter = it->constBegin();
00443     for ( ; iter != it->constEnd(); ++iter )
00444     {
00445       ++count;
00446     }
00447   }
00448   return count;
00449 }
00450 
00451 const QgsPoint *QgsRubberBand::getPoint( int i, int j ) const
00452 {
00453   if ( i < mPoints.size() && j < mPoints[i].size() )
00454     return &mPoints[i][j];
00455   else
00456     return 0;
00457 }
00458 
00459 QgsGeometry *QgsRubberBand::asGeometry()
00460 {
00461   QgsGeometry *geom = NULL;
00462   if ( mIsPolygon )
00463   {
00464     QgsPolygon polygon;
00465     QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
00466     for ( ; it != mPoints.constEnd(); ++it )
00467     {
00468       polygon.append( getPolyline( *it ) );
00469     }
00470     geom = QgsGeometry::fromPolygon( polygon );
00471   }
00472   else
00473   {
00474     if ( mPoints.size() > 0 )
00475     {
00476       if ( mPoints.size() > 1 )
00477       {
00478         QgsMultiPolyline multiPolyline;
00479         QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
00480         for ( ; it != mPoints.constEnd(); ++it )
00481         {
00482           multiPolyline.append( getPolyline( *it ) );
00483         }
00484         geom = QgsGeometry::fromMultiPolyline( multiPolyline );
00485       }
00486       else
00487       {
00488         geom = QgsGeometry::fromPolyline( getPolyline( mPoints[0] ) );
00489       }
00490     }
00491   }
00492   return geom;
00493 }
00494 
00495 QgsPolyline QgsRubberBand::getPolyline( const QList<QgsPoint> & points )
00496 {
00497   QgsPolyline polyline;
00498   QList<QgsPoint>::const_iterator iter = points.constBegin();
00499   for ( ; iter != points.constEnd(); ++iter )
00500   {
00501     polyline.append( *iter );
00502   }
00503   return polyline;
00504 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines