QGIS API Documentation  2.99.0-Master (0a63d1f)
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 "qgsvectorlayer.h"
22 #include <QPainter>
23 
30  : QgsMapCanvasItem( mapCanvas )
31  , mIconSize( 5 )
32  , mIconType( ICON_CIRCLE )
33  , mGeometryType( geometryType )
34  , mTranslationOffsetX( 0.0 )
35  , mTranslationOffsetY( 0.0 )
36 {
37  reset( geometryType );
38  QColor color( Qt::lightGray );
39  color.setAlpha( 63 );
40  setColor( color );
41  setWidth( 1 );
42  setLineStyle( Qt::SolidLine );
43  setBrushStyle( Qt::SolidPattern );
44 }
45 
47  : QgsMapCanvasItem( nullptr )
48  , mIconSize( 5 )
49  , mIconType( ICON_CIRCLE )
50  , mGeometryType( QgsWkbTypes::PolygonGeometry )
51  , mTranslationOffsetX( 0.0 )
52  , mTranslationOffsetY( 0.0 )
53 {
54 }
55 
59 void QgsRubberBand::setColor( const QColor & color )
60 {
61  setBorderColor( color );
62  setFillColor( color );
63 }
64 
68 void QgsRubberBand::setFillColor( const QColor & color )
69 {
70  QColor fillColor( color.red(), color.green(), color.blue(), color.alpha() );
71  mBrush.setColor( fillColor );
72 }
73 
77 void QgsRubberBand::setBorderColor( const QColor & color )
78 {
79  QColor penColor( color.red(), color.green(), color.blue(), color.alpha() );
80  mPen.setColor( penColor );
81 }
82 
83 
87 void QgsRubberBand::setWidth( int width )
88 {
89  mPen.setWidth( width );
90 }
91 
93 {
94  mIconType = icon;
95 }
96 
97 void QgsRubberBand::setIconSize( int iconSize )
98 {
99  mIconSize = iconSize;
100 }
101 
102 void QgsRubberBand::setLineStyle( Qt::PenStyle penStyle )
103 {
104  mPen.setStyle( penStyle );
105 }
106 
107 void QgsRubberBand::setBrushStyle( Qt::BrushStyle brushStyle )
108 {
109  mBrush.setStyle( brushStyle );
110 }
111 
116 {
117  mPoints.clear();
118  mGeometryType = geometryType;
119  updateRect();
120  update();
121 }
122 
126 void QgsRubberBand::addPoint( const QgsPoint & p, bool doUpdate /* = true */, int geometryIndex )
127 {
128  if ( geometryIndex < 0 )
129  {
130  geometryIndex = mPoints.size() - 1;
131  }
132 
133  if ( geometryIndex < 0 || geometryIndex > mPoints.size() )
134  {
135  return;
136  }
137 
138  if ( geometryIndex == mPoints.size() )
139  {
140  mPoints.push_back( QList<QgsPoint>() << p );
141  }
142 
143  if ( mPoints.at( geometryIndex ).size() == 2 &&
144  mPoints.at( geometryIndex ).at( 0 ) == mPoints.at( geometryIndex ).at( 1 ) )
145  {
146  mPoints[geometryIndex].last() = p;
147  }
148  else
149  {
150  mPoints[geometryIndex] << p;
151  }
152 
153 
154  if ( doUpdate )
155  {
156  setVisible( true );
157  updateRect();
158  update();
159  }
160 }
161 
162 void QgsRubberBand::closePoints( bool doUpdate, int geometryIndex )
163 {
164  if ( geometryIndex < 0 || geometryIndex >= mPoints.size() )
165  {
166  return;
167  }
168 
169  if ( mPoints.at( geometryIndex ).at( 0 ) != mPoints.at( geometryIndex ).at( mPoints.at( geometryIndex ).size() - 1 ) )
170  {
171  mPoints[geometryIndex] << mPoints.at( geometryIndex ).at( 0 );
172  }
173 
174  if ( doUpdate )
175  {
176  setVisible( true );
177  updateRect();
178  update();
179  }
180 }
181 
182 
183 void QgsRubberBand::removePoint( int index, bool doUpdate/* = true*/, int geometryIndex/* = 0*/ )
184 {
185 
186  if ( mPoints.size() < geometryIndex + 1 )
187  {
188  return;
189  }
190 
191 
192  if ( !mPoints[geometryIndex].isEmpty() )
193  {
194  // negative index removes from end, e.g., -1 removes last one
195  if ( index < 0 )
196  {
197  index = mPoints.at( geometryIndex ).size() + index;
198  }
199  mPoints[geometryIndex].removeAt( index );
200  }
201 
202  if ( doUpdate )
203  {
204  updateRect();
205  update();
206  }
207 }
208 
209 void QgsRubberBand::removeLastPoint( int geometryIndex, bool doUpdate/* = true*/ )
210 {
211  removePoint( -1, doUpdate, geometryIndex );
212 }
213 
217 void QgsRubberBand::movePoint( const QgsPoint & p, int geometryIndex )
218 {
219  if ( mPoints.size() < geometryIndex + 1 )
220  {
221  return;
222  }
223 
224  if ( mPoints.at( geometryIndex ).size() < 1 )
225  {
226  return;
227  }
228 
229  mPoints[geometryIndex].last() = p;
230 
231  updateRect();
232  update();
233 }
234 
235 void QgsRubberBand::movePoint( int index, const QgsPoint& p, int geometryIndex )
236 {
237  if ( mPoints.size() < geometryIndex + 1 )
238  {
239  return;
240  }
241 
242  if ( mPoints.at( geometryIndex ).size() < index )
243  {
244  return;
245  }
246 
247  mPoints[geometryIndex][index] = p;
248 
249  updateRect();
250  update();
251 }
252 
254 {
255  if ( geom.isEmpty() )
256  {
257  reset( mGeometryType );
258  return;
259  }
260 
261  reset( geom.type() );
262  addGeometry( geom, layer );
263 }
264 
266 {
267  if ( geom.isEmpty() )
268  {
269  return;
270  }
271 
272  //maprender object of canvas
273  const QgsMapSettings& ms = mMapCanvas->mapSettings();
274 
275  int idx = mPoints.size();
276 
277  switch ( geom.wkbType() )
278  {
279 
280  case QgsWkbTypes::Point:
282  {
283  QgsPoint pt;
284  if ( layer )
285  {
286  pt = ms.layerToMapCoordinates( layer, geom.asPoint() );
287  }
288  else
289  {
290  pt = geom.asPoint();
291  }
292  addPoint( pt, false, idx );
293  removeLastPoint( idx, false );
294  }
295  break;
296 
299  {
300  QgsMultiPoint mpt = geom.asMultiPoint();
301  for ( int i = 0; i < mpt.size(); ++i, ++idx )
302  {
303  QgsPoint pt = mpt[i];
304  if ( layer )
305  {
306  addPoint( ms.layerToMapCoordinates( layer, pt ), false, idx );
307  removeLastPoint( idx, false );
308  }
309  else
310  {
311  addPoint( pt, false, idx );
312  removeLastPoint( idx, false );
313  }
314  }
315  }
316  break;
317 
320  {
321  QgsPolyline line = geom.asPolyline();
322  for ( int i = 0; i < line.count(); i++ )
323  {
324  if ( layer )
325  {
326  addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx );
327  }
328  else
329  {
330  addPoint( line[i], false, idx );
331  }
332  }
333  }
334  break;
335 
338  {
339 
340  QgsMultiPolyline mline = geom.asMultiPolyline();
341  for ( int i = 0; i < mline.size(); ++i, ++idx )
342  {
343  QgsPolyline line = mline[i];
344 
345  if ( line.isEmpty() )
346  {
347  --idx;
348  }
349 
350  for ( int j = 0; j < line.size(); ++j )
351  {
352  if ( layer )
353  {
354  addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx );
355  }
356  else
357  {
358  addPoint( line[j], false, idx );
359  }
360  }
361  }
362  }
363  break;
364 
367  {
368  QgsPolygon poly = geom.asPolygon();
369  QgsPolyline line = poly[0];
370  for ( int i = 0; i < line.count(); i++ )
371  {
372  if ( layer )
373  {
374  addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx );
375  }
376  else
377  {
378  addPoint( line[i], false, idx );
379  }
380  }
381  }
382  break;
383 
386  {
387 
388  QgsMultiPolygon multipoly = geom.asMultiPolygon();
389  for ( int i = 0; i < multipoly.size(); ++i, ++idx )
390  {
391  QgsPolygon poly = multipoly[i];
392  QgsPolyline line = poly[0];
393  for ( int j = 0; j < line.count(); ++j )
394  {
395  if ( layer )
396  {
397  addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx );
398  }
399  else
400  {
401  addPoint( line[j], false, idx );
402  }
403  }
404  }
405  }
406  break;
407 
409  default:
410  return;
411  }
412 
413  setVisible( true );
414  updateRect();
415  update();
416 }
417 
419 {
420  if ( !mMapCanvas )
421  {
422  return;
423  }
424 
425  const QgsMapToPixel* transform = mMapCanvas->getCoordinateTransform();
426  QgsPoint ll = transform->toMapCoordinates( rect.left(), rect.bottom() );
427  QgsPoint lr = transform->toMapCoordinates( rect.right(), rect.bottom() );
428  QgsPoint ul = transform->toMapCoordinates( rect.left(), rect.top() );
429  QgsPoint ur = transform->toMapCoordinates( rect.right(), rect.top() );
430 
432  addPoint( ll, false );
433  addPoint( lr, false );
434  addPoint( ur, false );
435  addPoint( ul, true );
436 }
437 
441 void QgsRubberBand::paint( QPainter* p )
442 {
443  if ( !mPoints.isEmpty() )
444  {
445  p->setBrush( mBrush );
446  p->setPen( mPen );
447 
448  Q_FOREACH ( const QList<QgsPoint>& line, mPoints )
449  {
450  QVector<QPointF> pts;
451  Q_FOREACH ( const QgsPoint& pt, line )
452  {
453  const QPointF cur = toCanvasCoordinates( QgsPoint( pt.x() + mTranslationOffsetX, pt.y() + mTranslationOffsetY ) ) - pos();
454  if ( pts.empty() || std::abs( pts.back().x() - cur.x() ) > 1 || std::abs( pts.back().y() - cur.y() ) > 1 )
455  pts.append( cur );
456  }
457 
458  switch ( mGeometryType )
459  {
461  {
462  p->drawPolygon( pts );
463  }
464  break;
465 
467  {
468  Q_FOREACH ( QPointF pt, pts )
469  {
470  double x = pt.x();
471  double y = pt.y();
472 
473  qreal s = ( mIconSize - 1 ) / 2.0;
474 
475  switch ( mIconType )
476  {
477  case ICON_NONE:
478  break;
479 
480  case ICON_CROSS:
481  p->drawLine( QLineF( x - s, y, x + s, y ) );
482  p->drawLine( QLineF( x, y - s, x, y + s ) );
483  break;
484 
485  case ICON_X:
486  p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
487  p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
488  break;
489 
490  case ICON_BOX:
491  p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
492  p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
493  p->drawLine( QLineF( x + s, y + s, x - s, y + s ) );
494  p->drawLine( QLineF( x - s, y + s, x - s, y - s ) );
495  break;
496 
497  case ICON_FULL_BOX:
498  p->drawRect( x - s, y - s, mIconSize, mIconSize );
499  break;
500 
501  case ICON_CIRCLE:
502  p->drawEllipse( x - s, y - s, mIconSize, mIconSize );
503  break;
504  }
505  }
506  }
507  break;
508 
510  default:
511  {
512  p->drawPolyline( pts );
513  }
514  break;
515  }
516  }
517  }
518 }
519 
521 {
522  if ( mPoints.empty() )
523  {
524  setRect( QgsRectangle() );
525  setVisible( false );
526  return;
527  }
528 
529  const QgsMapToPixel& m2p = *( mMapCanvas->getCoordinateTransform() );
530 
531  qreal res = m2p.mapUnitsPerPixel();
532  qreal w = (( mIconSize - 1 ) / 2 + mPen.width() ) / res;
533 
534  QgsRectangle r;
535  for ( int i = 0; i < mPoints.size(); ++i )
536  {
537  QList<QgsPoint>::const_iterator it = mPoints.at( i ).constBegin(),
538  itE = mPoints.at( i ).constEnd();
539  for ( ; it != itE; ++it )
540  {
541  QgsPoint p( it->x() + mTranslationOffsetX, it->y() + mTranslationOffsetY );
542  p = m2p.transform( p );
543  QgsRectangle rect( p.x() - w, p.y() - w, p.x() + w, p.y() + w );
544 
545  if ( r.isEmpty() )
546  {
547  // Get rectangle of the first point
548  r = rect;
549  }
550  else
551  {
552  r.combineExtentWith( rect );
553  }
554  }
555  }
556 
557  // This is an hack to pass QgsMapCanvasItem::setRect what it
558  // expects (encoding of position and size of the item)
559  QgsPoint topLeft = m2p.toMapPoint( r.xMinimum(), r.yMinimum() );
560  QgsRectangle rect( topLeft.x(), topLeft.y(), topLeft.x() + r.width()*res, topLeft.y() - r.height()*res );
561 
562  setRect( rect );
563 }
564 
566 {
567  // re-compute rectangle
568  // See http://hub.qgis.org/issues/12392
569  // NOTE: could be optimized by saving map-extent
570  // of rubberband and simply re-projecting
571  // that to device-rectangle on "updatePosition"
572  updateRect();
573 }
574 
575 void QgsRubberBand::setTranslationOffset( double dx, double dy )
576 {
577  mTranslationOffsetX = dx;
578  mTranslationOffsetY = dy;
579  updateRect();
580 }
581 
583 {
584  return mPoints.size();
585 }
586 
587 int QgsRubberBand::partSize( int geometryIndex ) const
588 {
589  if ( geometryIndex < 0 || geometryIndex >= mPoints.size() ) return 0;
590  return mPoints[geometryIndex].size();
591 }
592 
594 {
595  int count = 0;
596  QList<QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
597  for ( ; it != mPoints.constEnd(); ++it )
598  {
599  QList<QgsPoint>::const_iterator iter = it->constBegin();
600  for ( ; iter != it->constEnd(); ++iter )
601  {
602  ++count;
603  }
604  }
605  return count;
606 }
607 
608 const QgsPoint *QgsRubberBand::getPoint( int i, int j ) const
609 {
610  if ( i < mPoints.size() && j < mPoints[i].size() )
611  return &mPoints[i][j];
612  else
613  return nullptr;
614 }
615 
617 {
618  QgsGeometry geom;
619 
620  switch ( mGeometryType )
621  {
623  {
624  QgsPolygon polygon;
625  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
626  for ( ; it != mPoints.constEnd(); ++it )
627  {
628  polygon.append( getPolyline( *it ) );
629  }
630  geom = QgsGeometry::fromPolygon( polygon );
631  break;
632  }
633 
635  {
636  QgsMultiPoint multiPoint;
637 
638  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
639  for ( ; it != mPoints.constEnd(); ++it )
640  {
641  multiPoint += getPolyline( *it );
642  }
643  geom = QgsGeometry::fromMultiPoint( multiPoint );
644  break;
645  }
646 
648  default:
649  {
650  if ( !mPoints.isEmpty() )
651  {
652  if ( mPoints.size() > 1 )
653  {
654  QgsMultiPolyline multiPolyline;
655  QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin();
656  for ( ; it != mPoints.constEnd(); ++it )
657  {
658  multiPolyline.append( getPolyline( *it ) );
659  }
660  geom = QgsGeometry::fromMultiPolyline( multiPolyline );
661  }
662  else
663  {
664  geom = QgsGeometry::fromPolyline( getPolyline( mPoints.at( 0 ) ) );
665  }
666  }
667  break;
668  }
669  }
670  return geom;
671 }
672 
673 QgsPolyline QgsRubberBand::getPolyline( const QList<QgsPoint> & points )
674 {
675  QgsPolyline polyline;
676  QList<QgsPoint>::const_iterator iter = points.constBegin();
677  for ( ; iter != points.constEnd(); ++iter )
678  {
679  polyline.append( *iter );
680  }
681  return polyline;
682 }
QgsPolygon asPolygon() const
Return contents of the geometry as a polygon if wkbType is WKBPolygon, otherwise an empty list...
A cross is used to highlight points (x)
Definition: qgsrubberband.h:54
void setIconSize(int iconSize)
Set the size of the point icons.
void setWidth(int width)
Set the width of the line.
static unsigned index
QgsMultiPolyline asMultiPolyline() const
Return contents of the geometry as a multi linestring if wkbType is WKBMultiLineString, otherwise an empty list.
A rectangle specified with double values.
Definition: qgsrectangle.h:36
double y
Definition: qgspoint.h:148
int numberOfVertices() const
Returns count of vertices in all lists of mPoint.
void setBorderColor(const QColor &color)
Set the border color for the rubberband.
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
QgsRectangle rect() const
returns canvas item rectangle in map units
void setToCanvasRectangle(QRect rect)
Sets this rubber band to a map canvas rectangle.
static QgsGeometry fromPolyline(const QgsPolyline &polyline)
Creates a new geometry from a QgsPolyline object.
void setTranslationOffset(double dx, double dy)
Adds translation to original coordinates (all in map coordinates)
void setLineStyle(Qt::PenStyle penStyle)
Set the style of the line.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
void movePoint(const QgsPoint &p, int geometryIndex=0)
Moves the rubber band point specified by index.
QVector< QgsPoint > QgsPolyline
Polyline is represented as a vector of points.
Definition: qgsgeometry.h:47
An abstract class for items that can be placed on the map canvas.
QgsPoint toMapPoint(double x, double y) const
QgsPoint toMapCoordinates(int x, int y) const
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:79
virtual void updatePosition() override
called on changed extent or resize event to update position of the item
A cross is used to highlight points (+)
Definition: qgsrubberband.h:49
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
const QgsPoint * getPoint(int i, int j=0) const
Return vertex.
QgsPolyline asPolyline() const
Return contents of the geometry as a polyline if wkbType is WKBLineString, otherwise an empty list...
virtual void paint(QPainter *p) override
The QgsMapSettings class contains configuration for rendering of the map.
void setToGeometry(const QgsGeometry &geom, QgsVectorLayer *layer)
Sets this rubber band to the geometry of an existing feature.
QgsRubberBand(QgsMapCanvas *mapCanvas, QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::LineGeometry)
Creates a new RubberBand.
QPointF toCanvasCoordinates(const QgsPoint &point) const
transformation from map coordinates to screen coordinates
QgsMultiPoint asMultiPoint() const
Return contents of the geometry as a multi point if wkbType is WKBMultiPoint, otherwise an empty list...
QgsPoint transform(const QgsPoint &p) const
Transform the point from map (world) coordinates to device coordinates.
void closePoints(bool doUpdate=true, int geometryIndex=0)
Ensures that a polygon geometry is closed and that the last vertex equals the first vertex...
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
QgsGeometry asGeometry() const
Returns the rubberband as a Geometry.
bool isEmpty() const
test if rectangle is empty.
A circle is used to highlight points (○)
Definition: qgsrubberband.h:64
void addGeometry(const QgsGeometry &geom, QgsVectorLayer *layer)
Add the geometry of an existing feature to a rubberband This is useful for multi feature highlighting...
void removePoint(int index=0, bool doUpdate=true, int geometryIndex=0)
Remove a vertex from the rubberband and (optionally) update canvas.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:212
void setRect(const QgsRectangle &r, bool resetRotation=true)
sets canvas item rectangle in map units
QVector< QgsPolygon > QgsMultiPolygon
A collection of QgsPolygons that share a common collection of attributes.
Definition: qgsgeometry.h:62
void addPoint(const QgsPoint &p, bool doUpdate=true, int geometryIndex=0)
Add a vertex to the rubberband and update canvas.
QVector< QgsPoint > QgsMultiPoint
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:56
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
void setFillColor(const QColor &color)
Set the fill color for the rubberband.
QVector< QgsPolyline > QgsPolygon
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
Definition: qgsgeometry.h:53
double mapUnitsPerPixel() const
Return current map units per pixel.
A class to represent a point.
Definition: qgspoint.h:143
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
static QgsGeometry fromPolygon(const QgsPolygon &polygon)
Creates a new geometry from a QgsPolygon.
QgsMapCanvasItem(QgsMapCanvas *mapCanvas)
protected constructor: cannot be constructed directly
void setBrushStyle(Qt::BrushStyle brushStyle)
Set the style of the brush.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:207
QVector< QgsPolyline > QgsMultiPolyline
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:59
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
void combineExtentWith(const QgsRectangle &rect)
expand the rectangle so that covers both the original rectangle and the given rectangle ...
void setIcon(IconType icon)
Set the icon type to highlight point geometries.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:131
A box is used to highlight points (□)
Definition: qgsrubberband.h:59
QgsPoint layerToMapCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from layer&#39;s CRS to output CRS
static QgsGeometry fromMultiPoint(const QgsMultiPoint &multipoint)
Creates a new geometry from a QgsMultiPoint object.
QgsMultiPolygon asMultiPolygon() const
Return contents of the geometry as a multi polygon if wkbType is WKBMultiPolygon, otherwise an empty ...
int partSize(int geometryIndex) const
Returns number of vertices in feature part.
QgsMapCanvas * mMapCanvas
pointer to map canvas
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:197
const QgsMapToPixel * getCoordinateTransform()
Get the current coordinate transform.
void reset(QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::LineGeometry)
Clears all the geometries in this rubberband.
void setColor(const QColor &color)
Set the color for the rubberband.
No icon is used.
Definition: qgsrubberband.h:44
int size() const
Returns number of geometries.
Represents a vector layer which manages a vector based data sets.
void removeLastPoint(int geometryIndex=0, bool doUpdate=true)
Removes the last point.
void updateRect()
recalculates needed rectangle
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:217
A full box is used to highlight points (■)
Definition: qgsrubberband.h:69
static QgsGeometry fromMultiPolyline(const QgsMultiPolyline &multiline)
Creates a new geometry from a QgsMultiPolyline object.
double x
Definition: qgspoint.h:147