QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
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 #include "qgsguiutils.h"
28 
29 #include <QPainter>
30 
32  : QObject( nullptr )
33  , QgsMapCanvasItem( mapCanvas )
34  , mGeometryType( geometryType )
35 {
36  reset( geometryType );
37  QColor color( Qt::lightGray );
38  color.setAlpha( 63 );
39  setColor( color );
40  setWidth( 1 );
41  setLineStyle( Qt::SolidLine );
42  setBrushStyle( Qt::SolidPattern );
43  setSecondaryStrokeColor( QColor() );
44 }
45 
46 QgsRubberBand::QgsRubberBand()
47  : QObject( nullptr )
48  , QgsMapCanvasItem( nullptr )
49 {
50 }
51 
53 
54 void QgsRubberBand::setColor( const QColor &color )
55 {
56  setStrokeColor( color );
57  setFillColor( color );
58 }
59 
60 void QgsRubberBand::setFillColor( const QColor &color )
61 {
62  if ( mBrush.color() == color )
63  return;
64 
65  mBrush.setColor( color );
66 }
67 
68 void QgsRubberBand::setStrokeColor( const QColor &color )
69 {
70  mPen.setColor( color );
71 }
72 
73 void QgsRubberBand::setSecondaryStrokeColor( const QColor &color )
74 {
75  mSecondaryPen.setColor( color );
76 }
77 
78 void QgsRubberBand::setWidth( int width )
79 {
80  mPen.setWidth( width );
81 }
82 
84 {
85  mIconType = icon;
86 }
87 
88 void QgsRubberBand::setSvgIcon( const QString &path, QPoint drawOffset )
89 {
90  setIcon( ICON_SVG );
91  mSvgRenderer = std::make_unique<QSvgRenderer>( path );
92  mSvgOffset = drawOffset;
93 }
94 
96 {
97  mIconSize = iconSize;
98 }
99 
100 void QgsRubberBand::setLineStyle( Qt::PenStyle penStyle )
101 {
102  mPen.setStyle( penStyle );
103 }
104 
105 void QgsRubberBand::setBrushStyle( Qt::BrushStyle brushStyle )
106 {
107  mBrush.setStyle( brushStyle );
108 }
109 
111 {
112  mPoints.clear();
113  mGeometryType = geometryType;
114  updateRect();
115  update();
116 }
117 
118 void QgsRubberBand::addPoint( const QgsPointXY &p, bool doUpdate /* = true */, int geometryIndex, int ringIndex )
119 {
120  if ( geometryIndex < 0 )
121  {
122  geometryIndex = mPoints.size() - 1;
123  }
124 
125  if ( geometryIndex < 0 || geometryIndex > mPoints.size() )
126  {
127  return;
128  }
129 
130  if ( geometryIndex == mPoints.size() )
131  {
132  // since we're adding a geometry, ringIndex must be 0 or negative for last ring
133  if ( ringIndex > 0 )
134  return;
135  mPoints.append( QgsPolygonXY() );
136  }
137 
138  // negative ringIndex means last ring
139  if ( ringIndex < 0 )
140  {
141  if ( mPoints.at( geometryIndex ).isEmpty() )
142  ringIndex = 0;
143  else
144  ringIndex = mPoints.at( geometryIndex ).size() - 1;
145  }
146 
147  if ( ringIndex > mPoints.at( geometryIndex ).size() )
148  return;
149 
150  if ( ringIndex == mPoints.at( geometryIndex ).size() )
151  {
152  mPoints[geometryIndex].append( QgsPolylineXY() );
153  if ( mGeometryType != Qgis::GeometryType::Point )
154  mPoints[geometryIndex][ringIndex].append( p );
155  }
156 
157  if ( mPoints.at( geometryIndex ).at( ringIndex ).size() == 2 &&
158  mPoints.at( geometryIndex ).at( ringIndex ).at( 0 ) == mPoints.at( geometryIndex ).at( ringIndex ).at( 1 ) )
159  {
160  mPoints[geometryIndex][ringIndex].last() = p;
161  }
162  else
163  {
164  mPoints[geometryIndex][ringIndex].append( p );
165  }
166 
167 
168  if ( doUpdate )
169  {
170  setVisible( true );
171  updateRect();
172  update();
173  }
174 }
175 
176 void QgsRubberBand::closePoints( bool doUpdate, int geometryIndex, int ringIndex )
177 {
178  if ( geometryIndex < 0 || ringIndex < 0 ||
179  mPoints.size() <= geometryIndex ||
180  mPoints.at( geometryIndex ).size() <= ringIndex ||
181  mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
182  {
183  return;
184  }
185 
186  if ( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() != mPoints.at( geometryIndex ).at( ringIndex ).constLast() )
187  {
188  mPoints[geometryIndex][ringIndex].append( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() );
189  }
190 
191  if ( doUpdate )
192  {
193  setVisible( true );
194  updateRect();
195  update();
196  }
197 }
198 
199 
200 void QgsRubberBand::removePoint( int index, bool doUpdate/* = true*/, int geometryIndex/* = 0*/, int ringIndex/* = 0*/ )
201 {
202 
203  if ( geometryIndex < 0 || ringIndex < 0 ||
204  mPoints.size() <= geometryIndex ||
205  mPoints.at( geometryIndex ).size() <= ringIndex ||
206  mPoints.at( geometryIndex ).at( ringIndex ).size() <= index ||
207  mPoints.at( geometryIndex ).at( ringIndex ).size() < -index ||
208  mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
209  {
210  return;
211  }
212 
213  // negative index removes from end, e.g., -1 removes last one
214  if ( index < 0 )
215  {
216  index = mPoints.at( geometryIndex ).at( ringIndex ).size() + index;
217  }
218  mPoints[geometryIndex][ringIndex].removeAt( index );
219 
220  if ( doUpdate )
221  {
222  updateRect();
223  update();
224  }
225 }
226 
227 void QgsRubberBand::removeLastPoint( int geometryIndex, bool doUpdate/* = true*/, int ringIndex/* = 0*/ )
228 {
229  removePoint( -1, doUpdate, geometryIndex, ringIndex );
230 }
231 
232 void QgsRubberBand::movePoint( const QgsPointXY &p, int geometryIndex, int ringIndex )
233 {
234  if ( geometryIndex < 0 || ringIndex < 0 ||
235  mPoints.size() <= geometryIndex ||
236  mPoints.at( geometryIndex ).size() <= ringIndex ||
237  mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
238  {
239  return;
240  }
241 
242  mPoints[geometryIndex][ringIndex].last() = p;
243 
244  updateRect();
245  update();
246 }
247 
248 void QgsRubberBand::movePoint( int index, const QgsPointXY &p, int geometryIndex, int ringIndex )
249 {
250  if ( geometryIndex < 0 || ringIndex < 0 || index < 0 ||
251  mPoints.size() <= geometryIndex ||
252  mPoints.at( geometryIndex ).size() <= ringIndex ||
253  mPoints.at( geometryIndex ).at( ringIndex ).size() <= index )
254  {
255  return;
256  }
257 
258  mPoints[geometryIndex][ringIndex][index] = p;
259 
260  updateRect();
261  update();
262 }
263 
265 {
266  if ( geom.isNull() )
267  {
268  reset( mGeometryType );
269  return;
270  }
271 
272  reset( geom.type() );
273  addGeometry( geom, layer );
274 }
275 
277 {
278  if ( geom.isNull() )
279  {
280  reset( mGeometryType );
281  return;
282  }
283 
284  reset( geom.type() );
285  addGeometry( geom, crs );
286 }
287 
288 void QgsRubberBand::addGeometry( const QgsGeometry &geometry, QgsMapLayer *layer, bool doUpdate )
289 {
290  QgsGeometry geom = geometry;
291  if ( layer )
292  {
294  try
295  {
296  geom.transform( ct );
297  }
298  catch ( QgsCsException & )
299  {
300  return;
301  }
302  }
303 
304  addGeometry( geom, QgsCoordinateReferenceSystem(), doUpdate );
305 }
306 
307 void QgsRubberBand::addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs, bool doUpdate )
308 {
309  if ( geometry.isEmpty() )
310  {
311  return;
312  }
313 
314  //maprender object of canvas
315  const QgsMapSettings &ms = mMapCanvas->mapSettings();
316 
317  int idx = mPoints.size();
318 
319  QgsGeometry geom = geometry;
320  if ( crs.isValid() )
321  {
323  try
324  {
325  geom.transform( ct );
326  }
327  catch ( QgsCsException & )
328  {
329  QgsDebugError( QStringLiteral( "Could not transform rubber band geometry to map CRS" ) );
330  return;
331  }
332  }
333 
334  Qgis::WkbType geomType = geom.wkbType();
336  {
337  QgsPointXY pt = geom.asPoint();
338  addPoint( pt, false, idx );
339  }
340  else if ( QgsWkbTypes::geometryType( geomType ) == Qgis::GeometryType::Point && QgsWkbTypes::isMultiType( geomType ) )
341  {
342  const QgsMultiPointXY mpt = geom.asMultiPoint();
343  for ( const QgsPointXY &pt : mpt )
344  {
345  addPoint( pt, false, idx );
346  idx++;
347  }
348  }
349  else if ( QgsWkbTypes::geometryType( geomType ) == Qgis::GeometryType::Line && !QgsWkbTypes::isMultiType( geomType ) )
350  {
351  const QgsPolylineXY line = geom.asPolyline();
352  for ( const QgsPointXY &pt : line )
353  {
354  addPoint( pt, false, idx );
355  }
356  }
357  else if ( QgsWkbTypes::geometryType( geomType ) == Qgis::GeometryType::Line && QgsWkbTypes::isMultiType( geomType ) )
358  {
359  const QgsMultiPolylineXY mline = geom.asMultiPolyline();
360  for ( const QgsPolylineXY &line : mline )
361  {
362  if ( line.isEmpty() )
363  {
364  continue;
365  }
366  for ( const QgsPointXY &pt : line )
367  {
368  addPoint( pt, false, idx );
369  }
370  idx++;
371  }
372  }
373  else if ( QgsWkbTypes::geometryType( geomType ) == Qgis::GeometryType::Polygon && !QgsWkbTypes::isMultiType( geomType ) )
374  {
375  const QgsPolygonXY poly = geom.asPolygon();
376  int ringIdx = 0;
377  for ( const QgsPolylineXY &ring : poly )
378  {
379  for ( const QgsPointXY &pt : ring )
380  {
381  addPoint( pt, false, idx, ringIdx );
382  }
383  ringIdx++;
384  }
385  }
386  else if ( QgsWkbTypes::geometryType( geomType ) == Qgis::GeometryType::Polygon && QgsWkbTypes::isMultiType( geomType ) )
387  {
388  const QgsMultiPolygonXY multipoly = geom.asMultiPolygon();
389  for ( const QgsPolygonXY &poly : multipoly )
390  {
391  if ( poly.isEmpty() )
392  continue;
393 
394  int ringIdx = 0;
395  for ( const QgsPolylineXY &ring : poly )
396  {
397  for ( const QgsPointXY &pt : ring )
398  {
399  addPoint( pt, false, idx, ringIdx );
400  }
401  ringIdx++;
402  }
403  idx++;
404  }
405  }
406  else
407  {
408  return;
409  }
410 
411  setVisible( true );
412  if ( doUpdate )
413  {
414  updateRect();
415  update();
416  }
417 }
418 
420 {
421  if ( !mMapCanvas )
422  {
423  return;
424  }
425 
426  const QgsMapToPixel *transform = mMapCanvas->getCoordinateTransform();
427  QgsPointXY ll = transform->toMapCoordinates( rect.left(), rect.bottom() );
428  QgsPointXY lr = transform->toMapCoordinates( rect.right(), rect.bottom() );
429  QgsPointXY ul = transform->toMapCoordinates( rect.left(), rect.top() );
430  QgsPointXY ur = transform->toMapCoordinates( rect.right(), rect.top() );
431 
433  addPoint( ll, false );
434  addPoint( lr, false );
435  addPoint( ur, false );
436  addPoint( ul, true );
437 }
438 
440 {
441  reset( other->mGeometryType );
442  mPoints = other->mPoints;
443  updateRect();
444  update();
445 }
446 
447 void QgsRubberBand::paint( QPainter *p )
448 {
449  if ( mPoints.isEmpty() )
450  return;
451 
452  QVector< QVector<QPolygonF> > shapes;
453  shapes.reserve( mPoints.size() );
454  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
455  {
456  QVector<QPolygonF> rings;
457  rings.reserve( poly.size() );
458  for ( const QgsPolylineXY &line : poly )
459  {
460  QVector<QPointF> pts;
461  pts.reserve( line.size() );
462  for ( const QgsPointXY &pt : line )
463  {
464  const QPointF cur = toCanvasCoordinates( QgsPointXY( pt.x() + mTranslationOffsetX, pt.y() + mTranslationOffsetY ) ) - pos();
465  if ( pts.isEmpty() || std::abs( pts.last().x() - cur.x() ) > 1 || std::abs( pts.last().y() - cur.y() ) > 1 )
466  pts.append( cur );
467  }
468  rings.append( pts );
469  }
470  shapes.append( rings );
471  }
472 
473  if ( QgsLineSymbol *lineSymbol = dynamic_cast< QgsLineSymbol * >( mSymbol.get() ) )
474  {
477 
478  lineSymbol->startRender( context );
479  for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
480  {
481  for ( const QPolygonF &ring : shape )
482  {
483  lineSymbol->renderPolyline( ring, nullptr, context );
484  }
485  }
486  lineSymbol->stopRender( context );
487  }
488  else if ( QgsFillSymbol *fillSymbol = dynamic_cast< QgsFillSymbol * >( mSymbol.get() ) )
489  {
492 
493  fillSymbol->startRender( context );
494  for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
495  {
496  for ( const QPolygonF &ring : shape )
497  {
498  fillSymbol->renderPolygon( ring, nullptr, nullptr, context );
499  }
500  }
501  fillSymbol->stopRender( context );
502  }
503  else
504  {
505  int iterations = mSecondaryPen.color().isValid() ? 2 : 1;
506  for ( int i = 0; i < iterations; ++i )
507  {
508  if ( i == 0 && iterations > 1 )
509  {
510  // first iteration with multi-pen painting, so use secondary pen
511  mSecondaryPen.setWidth( mPen.width() + QgsGuiUtils::scaleIconSize( 2 ) );
512  p->setBrush( Qt::NoBrush );
513  p->setPen( mSecondaryPen );
514  }
515  else
516  {
517  // "top" layer, use primary pen/brush
518  p->setBrush( mBrush );
519  p->setPen( mPen );
520  }
521 
522  for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
523  {
524  drawShape( p, shape );
525  }
526  }
527  }
528 }
529 
530 void QgsRubberBand::drawShape( QPainter *p, const QVector<QPolygonF> &rings )
531 {
532  if ( rings.size() == 1 )
533  {
534  drawShape( p, rings.at( 0 ) );
535  }
536  else
537  {
538  QPainterPath path;
539  for ( const QPolygonF &poly : rings )
540  {
541  path.addPolygon( poly );
542  }
543  p->drawPath( path );
544  }
545 }
546 
547 void QgsRubberBand::drawShape( QPainter *p, const QVector<QPointF> &pts )
548 {
549  switch ( mGeometryType )
550  {
552  {
553  p->drawPolygon( pts );
554  }
555  break;
556 
558  {
559  const auto constPts = pts;
560  for ( QPointF pt : constPts )
561  {
562  double x = pt.x();
563  double y = pt.y();
564 
565  qreal s = ( mIconSize - 1 ) / 2.0;
566 
567  switch ( mIconType )
568  {
569  case ICON_NONE:
570  break;
571 
572  case ICON_CROSS:
573  p->drawLine( QLineF( x - s, y, x + s, y ) );
574  p->drawLine( QLineF( x, y - s, x, y + s ) );
575  break;
576 
577  case ICON_X:
578  p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
579  p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
580  break;
581 
582  case ICON_BOX:
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  p->drawLine( QLineF( x - s, y + s, x - s, y - s ) );
587  break;
588 
589  case ICON_FULL_BOX:
590  p->drawRect( static_cast< int>( x - s ), static_cast< int >( y - s ), mIconSize, mIconSize );
591  break;
592 
593  case ICON_CIRCLE:
594  p->drawEllipse( static_cast< int >( x - s ), static_cast< int >( y - s ), mIconSize, mIconSize );
595  break;
596 
597  case ICON_DIAMOND:
598  case ICON_FULL_DIAMOND:
599  {
600  QPointF pts[] =
601  {
602  QPointF( x, y - s ),
603  QPointF( x + s, y ),
604  QPointF( x, y + s ),
605  QPointF( x - s, y )
606  };
607  if ( mIconType == ICON_FULL_DIAMOND )
608  p->drawPolygon( pts, 4 );
609  else
610  p->drawPolyline( pts, 4 );
611  break;
612  }
613 
614  case ICON_SVG:
615  {
616  QRectF viewBox = mSvgRenderer->viewBoxF();
617  QRectF r( mSvgOffset.x(), mSvgOffset.y(), viewBox.width(), viewBox.height() );
618  QgsScopedQPainterState painterState( p );
619  p->translate( pt );
620  mSvgRenderer->render( p, r );
621  break;
622  }
623  }
624  }
625  }
626  break;
627 
629  default:
630  {
631  p->drawPolyline( pts );
632  }
633  break;
634  }
635 }
636 
638 {
639  if ( mPoints.isEmpty() )
640  {
641  setRect( QgsRectangle() );
642  setVisible( false );
643  return;
644  }
645 
646  const QgsMapToPixel &m2p = *( mMapCanvas->getCoordinateTransform() );
647 
648 #if 0 // unused?
649  double iconSize = ( mIconSize + 1 ) / 2.;
650  if ( mSvgRenderer )
651  {
652  QRectF viewBox = mSvgRenderer->viewBoxF();
653  iconSize = std::max( std::fabs( mSvgOffset.x() ) + .5 * viewBox.width(), std::fabs( mSvgOffset.y() ) + .5 * viewBox.height() );
654  }
655 #endif
656 
657  qreal w = ( ( mIconSize - 1 ) / 2 + mPen.width() ); // in canvas units
658 
659  QgsRectangle r; // in canvas units
660  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
661  {
662  for ( const QgsPointXY &point : poly.at( 0 ) )
663  {
664  QgsPointXY p( point.x() + mTranslationOffsetX, point.y() + mTranslationOffsetY );
665  p = m2p.transform( p );
666  // no need to normalize the rectangle -- we know it is already normal
667  QgsRectangle rect( p.x() - w, p.y() - w, p.x() + w, p.y() + w, false );
668  r.combineExtentWith( rect );
669  }
670  }
671 
672  // This is an hack to pass QgsMapCanvasItem::setRect what it
673  // expects (encoding of position and size of the item)
674  qreal res = m2p.mapUnitsPerPixel();
675  QgsPointXY topLeft = m2p.toMapCoordinates( r.xMinimum(), r.yMinimum() );
676  QgsRectangle rect( topLeft.x(), topLeft.y(), topLeft.x() + r.width()*res, topLeft.y() - r.height()*res );
677 
678  setRect( rect );
679 }
680 
682 {
683  return mSymbol.get();
684 }
685 
687 {
688  mSymbol.reset( symbol );
689 }
690 
692 {
693  // re-compute rectangle
694  // See https://github.com/qgis/QGIS/issues/20566
695  // NOTE: could be optimized by saving map-extent
696  // of rubberband and simply re-projecting
697  // that to device-rectangle on "updatePosition"
698  updateRect();
699 }
700 
701 void QgsRubberBand::setTranslationOffset( double dx, double dy )
702 {
703  mTranslationOffsetX = dx;
704  mTranslationOffsetY = dy;
705  updateRect();
706 }
707 
709 {
710  return mPoints.size();
711 }
712 
713 int QgsRubberBand::partSize( int geometryIndex ) const
714 {
715  if ( geometryIndex < 0 ||
716  geometryIndex >= mPoints.size() ||
717  mPoints.at( geometryIndex ).isEmpty() )
718  return 0;
719  return mPoints.at( geometryIndex ).at( 0 ).size();
720 }
721 
723 {
724  int count = 0;
725  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
726  {
727  for ( const QgsPolylineXY &ring : poly )
728  {
729  count += ring.size();
730  }
731  }
732  return count;
733 }
734 
735 const QgsPointXY *QgsRubberBand::getPoint( int i, int j, int ringIndex ) const
736 {
737  if ( i < 0 || ringIndex < 0 || j < 0 ||
738  mPoints.size() <= i ||
739  mPoints.at( i ).size() <= ringIndex ||
740  mPoints.at( i ).at( ringIndex ).size() <= j )
741  return nullptr;
742  else
743  return &mPoints[i][ringIndex][j];
744 }
745 
747 {
748  QgsGeometry geom;
749 
750  switch ( mGeometryType )
751  {
753  {
754  geom = QgsGeometry::fromMultiPolygonXY( mPoints );
755  break;
756  }
757 
759  {
760  QgsMultiPointXY multiPoint;
761 
762  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
763  {
764  if ( poly.isEmpty() )
765  continue;
766  multiPoint.append( poly.at( 0 ) );
767  }
768  geom = QgsGeometry::fromMultiPointXY( multiPoint );
769  break;
770  }
771 
773  default:
774  {
775  if ( !mPoints.isEmpty() )
776  {
777  if ( mPoints.size() > 1 )
778  {
779  QgsMultiPolylineXY multiPolyline;
780  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
781  {
782  if ( poly.isEmpty() )
783  continue;
784  multiPolyline.append( poly.at( 0 ) );
785  }
786  geom = QgsGeometry::fromMultiPolylineXY( multiPolyline );
787  }
788  else
789  {
790  if ( !mPoints.at( 0 ).isEmpty() )
791  geom = QgsGeometry::fromPolylineXY( mPoints.at( 0 ).at( 0 ) );
792  else
794  }
795  }
796  break;
797  }
798  }
799  return geom;
800 }
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition: qgis.h:255
@ Polygon
Polygons.
@ Antialiasing
Use antialiasing while drawing.
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition: qgis.h:182
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:67
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:162
QgsMultiPolygonXY asMultiPolygon() const
Returns the contents of the geometry as a multi-polygon.
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)
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:164
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.
Qgis::GeometryType type
Definition: qgsgeometry.h:165
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...
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
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:93
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:75
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:88
A class to represent a 2D point.
Definition: qgspointxy.h:60
double y
Definition: qgspointxy.h:64
Q_GADGET double x
Definition: qgspointxy.h:63
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:481
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:201
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:211
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:236
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle.
Definition: qgsrectangle.h:413
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:243
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:54
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.
QgsRubberBand(QgsMapCanvas *mapCanvas, Qgis::GeometryType geometryType=Qgis::GeometryType::Line)
Creates a new RubberBand.
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 reset(Qgis::GeometryType geometryType=Qgis::GeometryType::Line)
Clears all the geometries in this rubberband.
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)
@ 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:90
@ ICON_CROSS
A cross is used to highlight points (+)
Definition: qgsrubberband.h:95
@ 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 (□)
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 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:94
Represents a vector layer which manages a vector based data sets.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:862
static bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:758
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item.
Definition: qgsgeometry.h:74
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:84
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:80
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:91
#define QgsDebugError(str)
Definition: qgslogger.h:38
const QgsCoordinateReferenceSystem & crs