QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 "qgsgeometry.h"
18 #include "qgslogger.h"
19 #include "qgsmapcanvas.h"
20 #include "qgsvectorlayer.h"
21 #include "qgsproject.h"
22 #include "qgsrectangle.h"
23 #include "qgssymbol.h"
24 #include "qgsrendercontext.h"
25 #include "qgslinesymbol.h"
26 #include "qgsfillsymbol.h"
27 
28 #include <QPainter>
29 
31  : QObject( nullptr )
32  , QgsMapCanvasItem( mapCanvas )
33  , mGeometryType( geometryType )
34 {
35  reset( geometryType );
36  QColor color( Qt::lightGray );
37  color.setAlpha( 63 );
38  setColor( color );
39  setWidth( 1 );
40  setLineStyle( Qt::SolidLine );
41  setBrushStyle( Qt::SolidPattern );
42  setSecondaryStrokeColor( QColor() );
43 }
44 
45 QgsRubberBand::QgsRubberBand()
46  : QObject( nullptr )
47  , QgsMapCanvasItem( nullptr )
48 {
49 }
50 
52 
53 void QgsRubberBand::setColor( const QColor &color )
54 {
55  setStrokeColor( color );
56  setFillColor( color );
57 }
58 
59 void QgsRubberBand::setFillColor( const QColor &color )
60 {
61  if ( mBrush.color() == color )
62  return;
63 
64  mBrush.setColor( color );
65 }
66 
67 void QgsRubberBand::setStrokeColor( const QColor &color )
68 {
69  mPen.setColor( color );
70 }
71 
72 void QgsRubberBand::setSecondaryStrokeColor( const QColor &color )
73 {
74  mSecondaryPen.setColor( color );
75 }
76 
77 void QgsRubberBand::setWidth( int width )
78 {
79  mPen.setWidth( width );
80 }
81 
83 {
84  mIconType = icon;
85 }
86 
87 void QgsRubberBand::setSvgIcon( const QString &path, QPoint drawOffset )
88 {
89  setIcon( ICON_SVG );
90  mSvgRenderer = std::make_unique<QSvgRenderer>( path );
91  mSvgOffset = drawOffset;
92 }
93 
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 
110 {
111  mPoints.clear();
112  mGeometryType = geometryType;
113  updateRect();
114  update();
115 }
116 
117 void QgsRubberBand::addPoint( const QgsPointXY &p, bool doUpdate /* = true */, int geometryIndex, int ringIndex )
118 {
119  if ( geometryIndex < 0 )
120  {
121  geometryIndex = mPoints.size() - 1;
122  }
123 
124  if ( geometryIndex < 0 || geometryIndex > mPoints.size() )
125  {
126  return;
127  }
128 
129  if ( geometryIndex == mPoints.size() )
130  {
131  // since we're adding a geometry, ringIndex must be 0 or negative for last ring
132  if ( ringIndex > 0 )
133  return;
134  mPoints.append( QgsPolygonXY() );
135  }
136 
137  // negative ringIndex means last ring
138  if ( ringIndex < 0 )
139  {
140  if ( mPoints.at( geometryIndex ).isEmpty() )
141  ringIndex = 0;
142  else
143  ringIndex = mPoints.at( geometryIndex ).size() - 1;
144  }
145 
146  if ( ringIndex > mPoints.at( geometryIndex ).size() )
147  return;
148 
149  if ( ringIndex == mPoints.at( geometryIndex ).size() )
150  {
151  mPoints[geometryIndex].append( QgsPolylineXY() );
152  if ( mGeometryType != QgsWkbTypes::PointGeometry )
153  mPoints[geometryIndex][ringIndex].append( p );
154  }
155 
156  if ( mPoints.at( geometryIndex ).at( ringIndex ).size() == 2 &&
157  mPoints.at( geometryIndex ).at( ringIndex ).at( 0 ) == mPoints.at( geometryIndex ).at( ringIndex ).at( 1 ) )
158  {
159  mPoints[geometryIndex][ringIndex].last() = p;
160  }
161  else
162  {
163  mPoints[geometryIndex][ringIndex].append( p );
164  }
165 
166 
167  if ( doUpdate )
168  {
169  setVisible( true );
170  updateRect();
171  update();
172  }
173 }
174 
175 void QgsRubberBand::closePoints( bool doUpdate, int geometryIndex, int ringIndex )
176 {
177  if ( geometryIndex < 0 || ringIndex < 0 ||
178  mPoints.size() <= geometryIndex ||
179  mPoints.at( geometryIndex ).size() <= ringIndex ||
180  mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
181  {
182  return;
183  }
184 
185  if ( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() != mPoints.at( geometryIndex ).at( ringIndex ).constLast() )
186  {
187  mPoints[geometryIndex][ringIndex].append( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() );
188  }
189 
190  if ( doUpdate )
191  {
192  setVisible( true );
193  updateRect();
194  update();
195  }
196 }
197 
198 
199 void QgsRubberBand::removePoint( int index, bool doUpdate/* = true*/, int geometryIndex/* = 0*/, int ringIndex/* = 0*/ )
200 {
201 
202  if ( geometryIndex < 0 || ringIndex < 0 ||
203  mPoints.size() <= geometryIndex ||
204  mPoints.at( geometryIndex ).size() <= ringIndex ||
205  mPoints.at( geometryIndex ).at( ringIndex ).size() <= index ||
206  mPoints.at( geometryIndex ).at( ringIndex ).size() < -index ||
207  mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
208  {
209  return;
210  }
211 
212  // negative index removes from end, e.g., -1 removes last one
213  if ( index < 0 )
214  {
215  index = mPoints.at( geometryIndex ).at( ringIndex ).size() + index;
216  }
217  mPoints[geometryIndex][ringIndex].removeAt( index );
218 
219  if ( doUpdate )
220  {
221  updateRect();
222  update();
223  }
224 }
225 
226 void QgsRubberBand::removeLastPoint( int geometryIndex, bool doUpdate/* = true*/, int ringIndex/* = 0*/ )
227 {
228  removePoint( -1, doUpdate, geometryIndex, ringIndex );
229 }
230 
231 void QgsRubberBand::movePoint( const QgsPointXY &p, int geometryIndex, int ringIndex )
232 {
233  if ( geometryIndex < 0 || ringIndex < 0 ||
234  mPoints.size() <= geometryIndex ||
235  mPoints.at( geometryIndex ).size() <= ringIndex ||
236  mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
237  {
238  return;
239  }
240 
241  mPoints[geometryIndex][ringIndex].last() = p;
242 
243  updateRect();
244  update();
245 }
246 
247 void QgsRubberBand::movePoint( int index, const QgsPointXY &p, int geometryIndex, int ringIndex )
248 {
249  if ( geometryIndex < 0 || ringIndex < 0 || index < 0 ||
250  mPoints.size() <= geometryIndex ||
251  mPoints.at( geometryIndex ).size() <= ringIndex ||
252  mPoints.at( geometryIndex ).at( ringIndex ).size() <= index )
253  {
254  return;
255  }
256 
257  mPoints[geometryIndex][ringIndex][index] = p;
258 
259  updateRect();
260  update();
261 }
262 
264 {
265  if ( geom.isNull() )
266  {
267  reset( mGeometryType );
268  return;
269  }
270 
271  reset( geom.type() );
272  addGeometry( geom, layer );
273 }
274 
276 {
277  if ( geom.isNull() )
278  {
279  reset( mGeometryType );
280  return;
281  }
282 
283  reset( geom.type() );
284  addGeometry( geom, crs );
285 }
286 
287 void QgsRubberBand::addGeometry( const QgsGeometry &geometry, QgsMapLayer *layer, bool doUpdate )
288 {
289  QgsGeometry geom = geometry;
290  if ( layer )
291  {
293  try
294  {
295  geom.transform( ct );
296  }
297  catch ( QgsCsException & )
298  {
299  return;
300  }
301  }
302 
303  addGeometry( geom, QgsCoordinateReferenceSystem(), doUpdate );
304 }
305 
306 void QgsRubberBand::addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs, bool doUpdate )
307 {
308  if ( geometry.isEmpty() )
309  {
310  return;
311  }
312 
313  //maprender object of canvas
314  const QgsMapSettings &ms = mMapCanvas->mapSettings();
315 
316  int idx = mPoints.size();
317 
318  QgsGeometry geom = geometry;
319  if ( crs.isValid() )
320  {
322  try
323  {
324  geom.transform( ct );
325  }
326  catch ( QgsCsException & )
327  {
328  QgsDebugMsg( QStringLiteral( "Could not transform rubber band geometry to map CRS" ) );
329  return;
330  }
331  }
332 
333  QgsWkbTypes::Type geomType = geom.wkbType();
335  {
336  QgsPointXY pt = geom.asPoint();
337  addPoint( pt, false, idx );
338  }
339  else if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::PointGeometry && QgsWkbTypes::isMultiType( geomType ) )
340  {
341  const QgsMultiPointXY mpt = geom.asMultiPoint();
342  for ( const QgsPointXY &pt : mpt )
343  {
344  addPoint( pt, false, idx );
345  idx++;
346  }
347  }
348  else if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::LineGeometry && !QgsWkbTypes::isMultiType( geomType ) )
349  {
350  const QgsPolylineXY line = geom.asPolyline();
351  for ( const QgsPointXY &pt : line )
352  {
353  addPoint( pt, false, idx );
354  }
355  }
356  else if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::LineGeometry && QgsWkbTypes::isMultiType( geomType ) )
357  {
358  const QgsMultiPolylineXY mline = geom.asMultiPolyline();
359  for ( const QgsPolylineXY &line : mline )
360  {
361  if ( line.isEmpty() )
362  {
363  continue;
364  }
365  for ( const QgsPointXY &pt : line )
366  {
367  addPoint( pt, false, idx );
368  }
369  idx++;
370  }
371  }
372  else if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::PolygonGeometry && !QgsWkbTypes::isMultiType( geomType ) )
373  {
374  const QgsPolygonXY poly = geom.asPolygon();
375  int ringIdx = 0;
376  for ( const QgsPolylineXY &ring : poly )
377  {
378  for ( const QgsPointXY &pt : ring )
379  {
380  addPoint( pt, false, idx, ringIdx );
381  }
382  ringIdx++;
383  }
384  }
386  {
387  const QgsMultiPolygonXY multipoly = geom.asMultiPolygon();
388  for ( const QgsPolygonXY &poly : multipoly )
389  {
390  if ( poly.isEmpty() )
391  continue;
392 
393  int ringIdx = 0;
394  for ( const QgsPolylineXY &ring : poly )
395  {
396  for ( const QgsPointXY &pt : ring )
397  {
398  addPoint( pt, false, idx, ringIdx );
399  }
400  ringIdx++;
401  }
402  idx++;
403  }
404  }
405  else
406  {
407  return;
408  }
409 
410  setVisible( true );
411  if ( doUpdate )
412  {
413  updateRect();
414  update();
415  }
416 }
417 
419 {
420  if ( !mMapCanvas )
421  {
422  return;
423  }
424 
425  const QgsMapToPixel *transform = mMapCanvas->getCoordinateTransform();
426  QgsPointXY ll = transform->toMapCoordinates( rect.left(), rect.bottom() );
427  QgsPointXY lr = transform->toMapCoordinates( rect.right(), rect.bottom() );
428  QgsPointXY ul = transform->toMapCoordinates( rect.left(), rect.top() );
429  QgsPointXY 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 
439 {
440  reset( other->mGeometryType );
441  mPoints = other->mPoints;
442  updateRect();
443  update();
444 }
445 
446 void QgsRubberBand::paint( QPainter *p )
447 {
448  if ( mPoints.isEmpty() )
449  return;
450 
451  QVector< QVector<QPolygonF> > shapes;
452  shapes.reserve( mPoints.size() );
453  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
454  {
455  QVector<QPolygonF> rings;
456  rings.reserve( poly.size() );
457  for ( const QgsPolylineXY &line : poly )
458  {
459  QVector<QPointF> pts;
460  pts.reserve( line.size() );
461  for ( const QgsPointXY &pt : line )
462  {
463  const QPointF cur = toCanvasCoordinates( QgsPointXY( pt.x() + mTranslationOffsetX, pt.y() + mTranslationOffsetY ) ) - pos();
464  if ( pts.isEmpty() || std::abs( pts.last().x() - cur.x() ) > 1 || std::abs( pts.last().y() - cur.y() ) > 1 )
465  pts.append( cur );
466  }
467  rings.append( pts );
468  }
469  shapes.append( rings );
470  }
471 
472  if ( QgsLineSymbol *lineSymbol = dynamic_cast< QgsLineSymbol * >( mSymbol.get() ) )
473  {
476 
477  lineSymbol->startRender( context );
478  for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
479  {
480  for ( const QPolygonF &ring : shape )
481  {
482  lineSymbol->renderPolyline( ring, nullptr, context );
483  }
484  }
485  lineSymbol->stopRender( context );
486  }
487  else if ( QgsFillSymbol *fillSymbol = dynamic_cast< QgsFillSymbol * >( mSymbol.get() ) )
488  {
491 
492  fillSymbol->startRender( context );
493  for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
494  {
495  for ( const QPolygonF &ring : shape )
496  {
497  fillSymbol->renderPolygon( ring, nullptr, nullptr, context );
498  }
499  }
500  fillSymbol->stopRender( context );
501  }
502  else
503  {
504  int iterations = mSecondaryPen.color().isValid() ? 2 : 1;
505  for ( int i = 0; i < iterations; ++i )
506  {
507  if ( i == 0 && iterations > 1 )
508  {
509  // first iteration with multi-pen painting, so use secondary pen
510  mSecondaryPen.setWidth( mPen.width() + 2 );
511  p->setBrush( Qt::NoBrush );
512  p->setPen( mSecondaryPen );
513  }
514  else
515  {
516  // "top" layer, use primary pen/brush
517  p->setBrush( mBrush );
518  p->setPen( mPen );
519  }
520 
521  for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
522  {
523  drawShape( p, shape );
524  }
525  }
526  }
527 }
528 
529 void QgsRubberBand::drawShape( QPainter *p, const QVector<QPolygonF> &rings )
530 {
531  if ( rings.size() == 1 )
532  {
533  drawShape( p, rings.at( 0 ) );
534  }
535  else
536  {
537  QPainterPath path;
538  for ( const QPolygonF &poly : rings )
539  {
540  path.addPolygon( poly );
541  }
542  p->drawPath( path );
543  }
544 }
545 
546 void QgsRubberBand::drawShape( QPainter *p, const QVector<QPointF> &pts )
547 {
548  switch ( mGeometryType )
549  {
551  {
552  p->drawPolygon( pts );
553  }
554  break;
555 
557  {
558  const auto constPts = pts;
559  for ( QPointF pt : constPts )
560  {
561  double x = pt.x();
562  double y = pt.y();
563 
564  qreal s = ( mIconSize - 1 ) / 2.0;
565 
566  switch ( mIconType )
567  {
568  case ICON_NONE:
569  break;
570 
571  case ICON_CROSS:
572  p->drawLine( QLineF( x - s, y, x + s, y ) );
573  p->drawLine( QLineF( x, y - s, x, y + s ) );
574  break;
575 
576  case ICON_X:
577  p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
578  p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
579  break;
580 
581  case ICON_BOX:
582  p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
583  p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
584  p->drawLine( QLineF( x + s, y + s, x - s, y + s ) );
585  p->drawLine( QLineF( x - s, y + s, x - s, y - s ) );
586  break;
587 
588  case ICON_FULL_BOX:
589  p->drawRect( static_cast< int>( x - s ), static_cast< int >( y - s ), mIconSize, mIconSize );
590  break;
591 
592  case ICON_CIRCLE:
593  p->drawEllipse( static_cast< int >( x - s ), static_cast< int >( y - s ), mIconSize, mIconSize );
594  break;
595 
596  case ICON_DIAMOND:
597  case ICON_FULL_DIAMOND:
598  {
599  QPointF pts[] =
600  {
601  QPointF( x, y - s ),
602  QPointF( x + s, y ),
603  QPointF( x, y + s ),
604  QPointF( x - s, y )
605  };
606  if ( mIconType == ICON_FULL_DIAMOND )
607  p->drawPolygon( pts, 4 );
608  else
609  p->drawPolyline( pts, 4 );
610  break;
611  }
612 
613  case ICON_SVG:
614  {
615  QRectF viewBox = mSvgRenderer->viewBoxF();
616  QRectF r( mSvgOffset.x(), mSvgOffset.y(), viewBox.width(), viewBox.height() );
617  QgsScopedQPainterState painterState( p );
618  p->translate( pt );
619  mSvgRenderer->render( p, r );
620  break;
621  }
622  }
623  }
624  }
625  break;
626 
628  default:
629  {
630  p->drawPolyline( pts );
631  }
632  break;
633  }
634 }
635 
637 {
638  if ( mPoints.isEmpty() )
639  {
640  setRect( QgsRectangle() );
641  setVisible( false );
642  return;
643  }
644 
645  const QgsMapToPixel &m2p = *( mMapCanvas->getCoordinateTransform() );
646 
647 #if 0 // unused?
648  double iconSize = ( mIconSize + 1 ) / 2.;
649  if ( mSvgRenderer )
650  {
651  QRectF viewBox = mSvgRenderer->viewBoxF();
652  iconSize = std::max( std::fabs( mSvgOffset.x() ) + .5 * viewBox.width(), std::fabs( mSvgOffset.y() ) + .5 * viewBox.height() );
653  }
654 #endif
655 
656  qreal w = ( ( mIconSize - 1 ) / 2 + mPen.width() ); // in canvas units
657 
658  QgsRectangle r; // in canvas units
659  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
660  {
661  for ( const QgsPointXY &point : poly.at( 0 ) )
662  {
663  QgsPointXY p( point.x() + mTranslationOffsetX, point.y() + mTranslationOffsetY );
664  p = m2p.transform( p );
665  // no need to normalize the rectangle -- we know it is already normal
666  QgsRectangle rect( p.x() - w, p.y() - w, p.x() + w, p.y() + w, false );
667  r.combineExtentWith( rect );
668  }
669  }
670 
671  // This is an hack to pass QgsMapCanvasItem::setRect what it
672  // expects (encoding of position and size of the item)
673  qreal res = m2p.mapUnitsPerPixel();
674  QgsPointXY topLeft = m2p.toMapCoordinates( r.xMinimum(), r.yMinimum() );
675  QgsRectangle rect( topLeft.x(), topLeft.y(), topLeft.x() + r.width()*res, topLeft.y() - r.height()*res );
676 
677  setRect( rect );
678 }
679 
681 {
682  return mSymbol.get();
683 }
684 
686 {
687  mSymbol.reset( symbol );
688 }
689 
691 {
692  // re-compute rectangle
693  // See https://github.com/qgis/QGIS/issues/20566
694  // NOTE: could be optimized by saving map-extent
695  // of rubberband and simply re-projecting
696  // that to device-rectangle on "updatePosition"
697  updateRect();
698 }
699 
700 void QgsRubberBand::setTranslationOffset( double dx, double dy )
701 {
702  mTranslationOffsetX = dx;
703  mTranslationOffsetY = dy;
704  updateRect();
705 }
706 
708 {
709  return mPoints.size();
710 }
711 
712 int QgsRubberBand::partSize( int geometryIndex ) const
713 {
714  if ( geometryIndex < 0 ||
715  geometryIndex >= mPoints.size() ||
716  mPoints.at( geometryIndex ).isEmpty() )
717  return 0;
718  return mPoints.at( geometryIndex ).at( 0 ).size();
719 }
720 
722 {
723  int count = 0;
724  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
725  {
726  for ( const QgsPolylineXY &ring : poly )
727  {
728  count += ring.size();
729  }
730  }
731  return count;
732 }
733 
734 const QgsPointXY *QgsRubberBand::getPoint( int i, int j, int ringIndex ) const
735 {
736  if ( i < 0 || ringIndex < 0 || j < 0 ||
737  mPoints.size() <= i ||
738  mPoints.at( i ).size() <= ringIndex ||
739  mPoints.at( i ).at( ringIndex ).size() <= j )
740  return nullptr;
741  else
742  return &mPoints[i][ringIndex][j];
743 }
744 
746 {
747  QgsGeometry geom;
748 
749  switch ( mGeometryType )
750  {
752  {
753  geom = QgsGeometry::fromMultiPolygonXY( mPoints );
754  break;
755  }
756 
758  {
759  QgsMultiPointXY multiPoint;
760 
761  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
762  {
763  if ( poly.isEmpty() )
764  continue;
765  multiPoint.append( poly.at( 0 ) );
766  }
767  geom = QgsGeometry::fromMultiPointXY( multiPoint );
768  break;
769  }
770 
772  default:
773  {
774  if ( !mPoints.isEmpty() )
775  {
776  if ( mPoints.size() > 1 )
777  {
778  QgsMultiPolylineXY multiPolyline;
779  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
780  {
781  if ( poly.isEmpty() )
782  continue;
783  multiPolyline.append( poly.at( 0 ) );
784  }
785  geom = QgsGeometry::fromMultiPolylineXY( multiPolyline );
786  }
787  else
788  {
789  if ( !mPoints.at( 0 ).isEmpty() )
790  geom = QgsGeometry::fromPolylineXY( mPoints.at( 0 ).at( 0 ) );
791  else
793  }
794  }
795  break;
796  }
797  }
798  return geom;
799 }
@ Antialiasing
Use antialiasing while drawing.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgsfillsymbol.h:30
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
QgsMultiPolygonXY asMultiPolygon() const
Returns the contents of the geometry as a multi-polygon.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
static QgsGeometry fromMultiPolylineXY(const QgsMultiPolylineXY &multiline)
Creates a new geometry from a QgsMultiPolylineXY object.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
static QgsGeometry fromPolylineXY(const QgsPolylineXY &polyline)
Creates a new LineString geometry from a list of QgsPointXY points.
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.
Q_GADGET bool isNull
Definition: qgsgeometry.h:127
static QgsGeometry fromMultiPointXY(const QgsMultiPointXY &multipoint)
Creates a new geometry from a QgsMultiPointXY object.
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:128
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
static QgsGeometry fromMultiPolygonXY(const QgsMultiPolygonXY &multipoly)
Creates a new geometry from a QgsMultiPolygonXY.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
An abstract class for items that can be placed on the map canvas.
QgsRectangle rect() const
returns canvas item rectangle in map units
QPointF toCanvasCoordinates(const QgsPointXY &point) const
transformation from map coordinates to screen coordinates
QgsMapCanvas * mMapCanvas
pointer to map canvas
void setRect(const QgsRectangle &r, bool resetRotation=true)
sets canvas item rectangle in map units
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
const QgsMapToPixel * getCoordinateTransform()
Gets the current coordinate transform.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
The QgsMapSettings class contains configuration for rendering of the map.
QgsCoordinateTransform layerTransform(const QgsMapLayer *layer) const
Returns the coordinate transform from layer's CRS to destination CRS.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
double mapUnitsPerPixel() const
Returns the current map units per pixel.
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:90
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:470
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
Definition: qgsrectangle.h:391
Contains information about the context of a rendering operation.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
A class for drawing transient features (e.g.
Definition: qgsrubberband.h:52
QgsRubberBand(QgsMapCanvas *mapCanvas, QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::LineGeometry)
Creates a new RubberBand.
void closePoints(bool doUpdate=true, int geometryIndex=0, int ringIndex=0)
Ensures that a polygon geometry is closed and that the last vertex equals the first vertex.
~QgsRubberBand() override
void setWidth(int width)
Sets the width of the line.
void setSymbol(QgsSymbol *symbol)
Sets the symbol used for rendering the rubberband.
void removeLastPoint(int geometryIndex=0, bool doUpdate=true, int ringIndex=0)
Removes the last point.
void movePoint(const QgsPointXY &p, int geometryIndex=0, int ringIndex=0)
Moves the rubber band point specified by index.
QgsGeometry asGeometry() const
Returns the rubberband as a Geometry.
int size() const
Returns number of geometries.
void paint(QPainter *p) override
Paints the rubber band in response to an update event.
IconType icon() const
Returns the current icon type to highlight point geometries.
int partSize(int geometryIndex) const
Returns number of vertices in feature part.
void setSvgIcon(const QString &path, QPoint drawOffset)
Set the path to the svg file to use to draw points.
void setSecondaryStrokeColor(const QColor &color)
Sets a secondary stroke color for the rubberband which will be drawn under the main stroke color.
@ ICON_X
A cross is used to highlight points (x)
Definition: qgsrubberband.h:92
@ ICON_FULL_DIAMOND
A diamond is used to highlight points (◆)
@ ICON_FULL_BOX
A full box is used to highlight points (■)
@ ICON_NONE
No icon is used.
Definition: qgsrubberband.h:82
@ ICON_CROSS
A cross is used to highlight points (+)
Definition: qgsrubberband.h:87
@ ICON_SVG
An svg image is used to highlight points.
@ ICON_CIRCLE
A circle is used to highlight points (○)
@ ICON_DIAMOND
A diamond is used to highlight points (◇)
@ ICON_BOX
A box is used to highlight points (□)
Definition: qgsrubberband.h:97
const QgsPointXY * getPoint(int i, int j=0, int ringIndex=0) const
Returns a vertex.
void setColor(const QColor &color)
Sets the color for the rubberband.
void setToGeometry(const QgsGeometry &geom, QgsVectorLayer *layer)
Sets this rubber band to geom.
void setStrokeColor(const QColor &color)
Sets the stroke color for the rubberband.
void setLineStyle(Qt::PenStyle penStyle)
Sets the style of the line.
void updateRect()
Recalculates needed rectangle.
QgsSymbol * symbol() const
Returns the symbol used for rendering the rubberband, if set.
void setIconSize(int iconSize)
Sets the size of the point icons.
void setToCanvasRectangle(QRect rect)
Sets this rubber band to a map canvas rectangle.
void setIcon(IconType icon)
Sets the icon type to highlight point geometries.
void setBrushStyle(Qt::BrushStyle brushStyle)
Sets the style of the brush.
void reset(QgsWkbTypes::GeometryType geometryType=QgsWkbTypes::LineGeometry)
Clears all the geometries in this rubberband.
void updatePosition() override
called on changed extent or resize event to update position of the item
void copyPointsFrom(const QgsRubberBand *other)
Copies the points from another rubber band.
int numberOfVertices() const
Returns count of vertices in all lists of mPoint.
void addGeometry(const QgsGeometry &geometry, QgsMapLayer *layer, bool doUpdate=true)
Adds the geometry of an existing feature to a rubberband This is useful for multi feature highlightin...
void removePoint(int index=0, bool doUpdate=true, int geometryIndex=0, int ringIndex=0)
Removes a vertex from the rubberband and (optionally) updates canvas.
void setTranslationOffset(double dx, double dy)
Adds translation to original coordinates (all in map coordinates)
void setFillColor(const QColor &color)
Sets the fill color for the rubberband.
void drawShape(QPainter *p, const QVector< QPointF > &pts)
Draws shape of the rubber band.
void addPoint(const QgsPointXY &p, bool doUpdate=true, int geometryIndex=0, int ringIndex=0)
Adds a vertex to the rubberband and update canvas.
Scoped object for saving and restoring a QPainter object's state.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:38
Represents a vector layer which manages a vector based data sets.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:968
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:862
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item.
Definition: qgsgeometry.h:76
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:86
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:82
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:52
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
Definition: qgsgeometry.h:93
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
const QgsCoordinateReferenceSystem & crs