|
QGIS API Documentation
master-3f58142
|
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 }