QGIS API Documentation  3.20.0-Odense (decaadbb31)
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  mPoints[geometryIndex][ringIndex].append( p );
153  }
154 
155  if ( mPoints.at( geometryIndex ).at( ringIndex ).size() == 2 &&
156  mPoints.at( geometryIndex ).at( ringIndex ).at( 0 ) == mPoints.at( geometryIndex ).at( ringIndex ).at( 1 ) )
157  {
158  mPoints[geometryIndex][ringIndex].last() = p;
159  }
160  else
161  {
162  mPoints[geometryIndex][ringIndex].append( p );
163  }
164 
165 
166  if ( doUpdate )
167  {
168  setVisible( true );
169  updateRect();
170  update();
171  }
172 }
173 
174 void QgsRubberBand::closePoints( bool doUpdate, int geometryIndex, int ringIndex )
175 {
176  if ( geometryIndex < 0 || ringIndex < 0 ||
177  mPoints.size() <= geometryIndex ||
178  mPoints.at( geometryIndex ).size() <= ringIndex ||
179  mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
180  {
181  return;
182  }
183 
184  if ( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() != mPoints.at( geometryIndex ).at( ringIndex ).constLast() )
185  {
186  mPoints[geometryIndex][ringIndex].append( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() );
187  }
188 
189  if ( doUpdate )
190  {
191  setVisible( true );
192  updateRect();
193  update();
194  }
195 }
196 
197 
198 void QgsRubberBand::removePoint( int index, bool doUpdate/* = true*/, int geometryIndex/* = 0*/, int ringIndex/* = 0*/ )
199 {
200 
201  if ( geometryIndex < 0 || ringIndex < 0 ||
202  mPoints.size() <= geometryIndex ||
203  mPoints.at( geometryIndex ).size() <= ringIndex ||
204  mPoints.at( geometryIndex ).at( ringIndex ).size() <= index ||
205  mPoints.at( geometryIndex ).at( ringIndex ).size() < -index ||
206  mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
207  {
208  return;
209  }
210 
211  // negative index removes from end, e.g., -1 removes last one
212  if ( index < 0 )
213  {
214  index = mPoints.at( geometryIndex ).at( ringIndex ).size() + index;
215  }
216  mPoints[geometryIndex][ringIndex].removeAt( index );
217 
218  if ( doUpdate )
219  {
220  updateRect();
221  update();
222  }
223 }
224 
225 void QgsRubberBand::removeLastPoint( int geometryIndex, bool doUpdate/* = true*/, int ringIndex/* = 0*/ )
226 {
227  removePoint( -1, doUpdate, geometryIndex, ringIndex );
228 }
229 
230 void QgsRubberBand::movePoint( const QgsPointXY &p, int geometryIndex, int ringIndex )
231 {
232  if ( geometryIndex < 0 || ringIndex < 0 ||
233  mPoints.size() <= geometryIndex ||
234  mPoints.at( geometryIndex ).size() <= ringIndex ||
235  mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
236  {
237  return;
238  }
239 
240  mPoints[geometryIndex][ringIndex].last() = p;
241 
242  updateRect();
243  update();
244 }
245 
246 void QgsRubberBand::movePoint( int index, const QgsPointXY &p, int geometryIndex, int ringIndex )
247 {
248  if ( geometryIndex < 0 || ringIndex < 0 || index < 0 ||
249  mPoints.size() <= geometryIndex ||
250  mPoints.at( geometryIndex ).size() <= ringIndex ||
251  mPoints.at( geometryIndex ).at( ringIndex ).size() <= index )
252  {
253  return;
254  }
255 
256  mPoints[geometryIndex][ringIndex][index] = p;
257 
258  updateRect();
259  update();
260 }
261 
263 {
264  if ( geom.isNull() )
265  {
266  reset( mGeometryType );
267  return;
268  }
269 
270  reset( geom.type() );
271  addGeometry( geom, layer );
272 }
273 
275 {
276  if ( geom.isNull() )
277  {
278  reset( mGeometryType );
279  return;
280  }
281 
282  reset( geom.type() );
283  addGeometry( geom, crs );
284 }
285 
286 void QgsRubberBand::addGeometry( const QgsGeometry &geometry, QgsVectorLayer *layer, bool doUpdate )
287 {
288  QgsGeometry geom = geometry;
289  if ( layer )
290  {
292  try
293  {
294  geom.transform( ct );
295  }
296  catch ( QgsCsException & )
297  {
298  return;
299  }
300  }
301 
302  addGeometry( geom, QgsCoordinateReferenceSystem(), doUpdate );
303 }
304 
305 void QgsRubberBand::addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs, bool doUpdate )
306 {
307  if ( geometry.isEmpty() )
308  {
309  return;
310  }
311 
312  //maprender object of canvas
313  const QgsMapSettings &ms = mMapCanvas->mapSettings();
314 
315  int idx = mPoints.size();
316 
317  QgsGeometry geom = geometry;
318  if ( crs.isValid() )
319  {
321  try
322  {
323  geom.transform( ct );
324  }
325  catch ( QgsCsException & )
326  {
327  QgsDebugMsg( QStringLiteral( "Could not transform rubber band geometry to map CRS" ) );
328  return;
329  }
330  }
331 
332  QgsWkbTypes::Type geomType = geom.wkbType();
334  {
335  QgsPointXY pt = geom.asPoint();
336  addPoint( pt, false, idx );
337  removeLastPoint( idx, false );
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  removeLastPoint( idx, false );
346  idx++;
347  }
348  }
349  else if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::LineGeometry && !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 ) == QgsWkbTypes::LineGeometry && 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 ) == QgsWkbTypes::PolygonGeometry && !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  }
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 
439 void QgsRubberBand::paint( QPainter *p )
440 {
441  if ( mPoints.isEmpty() )
442  return;
443 
444  QVector< QVector<QPolygonF> > shapes;
445  shapes.reserve( mPoints.size() );
446  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
447  {
448  QVector<QPolygonF> rings;
449  rings.reserve( poly.size() );
450  for ( const QgsPolylineXY &line : poly )
451  {
452  QVector<QPointF> pts;
453  pts.reserve( line.size() );
454  for ( const QgsPointXY &pt : line )
455  {
456  const QPointF cur = toCanvasCoordinates( QgsPointXY( pt.x() + mTranslationOffsetX, pt.y() + mTranslationOffsetY ) ) - pos();
457  if ( pts.isEmpty() || std::abs( pts.last().x() - cur.x() ) > 1 || std::abs( pts.last().y() - cur.y() ) > 1 )
458  pts.append( cur );
459  }
460  rings.append( pts );
461  }
462  shapes.append( rings );
463  }
464 
465  if ( QgsLineSymbol *lineSymbol = dynamic_cast< QgsLineSymbol * >( mSymbol.get() ) )
466  {
468  context.setFlag( QgsRenderContext::Antialiasing, true );
469 
470  lineSymbol->startRender( context );
471  for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
472  {
473  for ( const QPolygonF &ring : shape )
474  {
475  lineSymbol->renderPolyline( ring, nullptr, context );
476  }
477  }
478  lineSymbol->stopRender( context );
479  }
480  else if ( QgsFillSymbol *fillSymbol = dynamic_cast< QgsFillSymbol * >( mSymbol.get() ) )
481  {
483  context.setFlag( QgsRenderContext::Antialiasing, true );
484 
485  fillSymbol->startRender( context );
486  for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
487  {
488  for ( const QPolygonF &ring : shape )
489  {
490  fillSymbol->renderPolygon( ring, nullptr, nullptr, context );
491  }
492  }
493  fillSymbol->stopRender( context );
494  }
495  else
496  {
497  int iterations = mSecondaryPen.color().isValid() ? 2 : 1;
498  for ( int i = 0; i < iterations; ++i )
499  {
500  if ( i == 0 && iterations > 1 )
501  {
502  // first iteration with multi-pen painting, so use secondary pen
503  mSecondaryPen.setWidth( mPen.width() + 2 );
504  p->setBrush( Qt::NoBrush );
505  p->setPen( mSecondaryPen );
506  }
507  else
508  {
509  // "top" layer, use primary pen/brush
510  p->setBrush( mBrush );
511  p->setPen( mPen );
512  }
513 
514  for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
515  {
516  drawShape( p, shape );
517  }
518  }
519  }
520 }
521 
522 void QgsRubberBand::drawShape( QPainter *p, const QVector<QPolygonF> &rings )
523 {
524  if ( rings.size() == 1 )
525  {
526  drawShape( p, rings.at( 0 ) );
527  }
528  else
529  {
530  QPainterPath path;
531  for ( const QPolygonF &poly : rings )
532  {
533  path.addPolygon( poly );
534  }
535  p->drawPath( path );
536  }
537 }
538 
539 void QgsRubberBand::drawShape( QPainter *p, const QVector<QPointF> &pts )
540 {
541  switch ( mGeometryType )
542  {
544  {
545  p->drawPolygon( pts );
546  }
547  break;
548 
550  {
551  const auto constPts = pts;
552  for ( QPointF pt : constPts )
553  {
554  double x = pt.x();
555  double y = pt.y();
556 
557  qreal s = ( mIconSize - 1 ) / 2.0;
558 
559  switch ( mIconType )
560  {
561  case ICON_NONE:
562  break;
563 
564  case ICON_CROSS:
565  p->drawLine( QLineF( x - s, y, x + s, y ) );
566  p->drawLine( QLineF( x, y - s, x, y + s ) );
567  break;
568 
569  case ICON_X:
570  p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
571  p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
572  break;
573 
574  case ICON_BOX:
575  p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
576  p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
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_FULL_BOX:
582  p->drawRect( static_cast< int>( x - s ), static_cast< int >( y - s ), mIconSize, mIconSize );
583  break;
584 
585  case ICON_CIRCLE:
586  p->drawEllipse( static_cast< int >( x - s ), static_cast< int >( y - s ), mIconSize, mIconSize );
587  break;
588 
589  case ICON_DIAMOND:
590  case ICON_FULL_DIAMOND:
591  {
592  QPointF pts[] =
593  {
594  QPointF( x, y - s ),
595  QPointF( x + s, y ),
596  QPointF( x, y + s ),
597  QPointF( x - s, y )
598  };
599  if ( mIconType == ICON_FULL_DIAMOND )
600  p->drawPolygon( pts, 4 );
601  else
602  p->drawPolyline( pts, 4 );
603  break;
604  }
605 
606  case ICON_SVG:
607  {
608  QRectF viewBox = mSvgRenderer->viewBoxF();
609  QRectF r( mSvgOffset.x(), mSvgOffset.y(), viewBox.width(), viewBox.height() );
610  QgsScopedQPainterState painterState( p );
611  p->translate( pt );
612  mSvgRenderer->render( p, r );
613  break;
614  }
615  }
616  }
617  }
618  break;
619 
621  default:
622  {
623  p->drawPolyline( pts );
624  }
625  break;
626  }
627 }
628 
630 {
631  if ( mPoints.isEmpty() )
632  {
633  setRect( QgsRectangle() );
634  setVisible( false );
635  return;
636  }
637 
638  const QgsMapToPixel &m2p = *( mMapCanvas->getCoordinateTransform() );
639 
640 #if 0 // unused?
641  double iconSize = ( mIconSize + 1 ) / 2.;
642  if ( mSvgRenderer )
643  {
644  QRectF viewBox = mSvgRenderer->viewBoxF();
645  iconSize = std::max( std::fabs( mSvgOffset.x() ) + .5 * viewBox.width(), std::fabs( mSvgOffset.y() ) + .5 * viewBox.height() );
646  }
647 #endif
648 
649  qreal w = ( ( mIconSize - 1 ) / 2 + mPen.width() ); // in canvas units
650 
651  QgsRectangle r; // in canvas units
652  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
653  {
654  for ( const QgsPointXY &point : poly.at( 0 ) )
655  {
656  QgsPointXY p( point.x() + mTranslationOffsetX, point.y() + mTranslationOffsetY );
657  p = m2p.transform( p );
658  // no need to normalize the rectangle -- we know it is already normal
659  QgsRectangle rect( p.x() - w, p.y() - w, p.x() + w, p.y() + w, false );
660  r.combineExtentWith( rect );
661  }
662  }
663 
664  // This is an hack to pass QgsMapCanvasItem::setRect what it
665  // expects (encoding of position and size of the item)
666  qreal res = m2p.mapUnitsPerPixel();
667  QgsPointXY topLeft = m2p.toMapCoordinates( r.xMinimum(), r.yMinimum() );
668  QgsRectangle rect( topLeft.x(), topLeft.y(), topLeft.x() + r.width()*res, topLeft.y() - r.height()*res );
669 
670  setRect( rect );
671 }
672 
674 {
675  return mSymbol.get();
676 }
677 
679 {
680  mSymbol.reset( symbol );
681 }
682 
684 {
685  // re-compute rectangle
686  // See https://github.com/qgis/QGIS/issues/20566
687  // NOTE: could be optimized by saving map-extent
688  // of rubberband and simply re-projecting
689  // that to device-rectangle on "updatePosition"
690  updateRect();
691 }
692 
693 void QgsRubberBand::setTranslationOffset( double dx, double dy )
694 {
695  mTranslationOffsetX = dx;
696  mTranslationOffsetY = dy;
697  updateRect();
698 }
699 
701 {
702  return mPoints.size();
703 }
704 
705 int QgsRubberBand::partSize( int geometryIndex ) const
706 {
707  if ( geometryIndex < 0 ||
708  geometryIndex >= mPoints.size() ||
709  mPoints.at( geometryIndex ).isEmpty() )
710  return 0;
711  return mPoints.at( geometryIndex ).at( 0 ).size();
712 }
713 
715 {
716  int count = 0;
717  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
718  {
719  for ( const QgsPolylineXY &ring : poly )
720  {
721  count += ring.size();
722  }
723  }
724  return count;
725 }
726 
727 const QgsPointXY *QgsRubberBand::getPoint( int i, int j, int ringIndex ) const
728 {
729  if ( i < 0 || ringIndex < 0 || j < 0 ||
730  mPoints.size() <= i ||
731  mPoints.at( i ).size() <= ringIndex ||
732  mPoints.at( i ).at( ringIndex ).size() <= j )
733  return nullptr;
734  else
735  return &mPoints[i][ringIndex][j];
736 }
737 
739 {
740  QgsGeometry geom;
741 
742  switch ( mGeometryType )
743  {
745  {
746  geom = QgsGeometry::fromMultiPolygonXY( mPoints );
747  break;
748  }
749 
751  {
752  QgsMultiPointXY multiPoint;
753 
754  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
755  {
756  if ( poly.isEmpty() )
757  continue;
758  multiPoint.append( poly.at( 0 ) );
759  }
760  geom = QgsGeometry::fromMultiPointXY( multiPoint );
761  break;
762  }
763 
765  default:
766  {
767  if ( !mPoints.isEmpty() )
768  {
769  if ( mPoints.size() > 1 )
770  {
771  QgsMultiPolylineXY multiPolyline;
772  for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
773  {
774  if ( poly.isEmpty() )
775  continue;
776  multiPolyline.append( poly.at( 0 ) );
777  }
778  geom = QgsGeometry::fromMultiPolylineXY( multiPolyline );
779  }
780  else
781  {
782  if ( !mPoints.at( 0 ).isEmpty() )
783  geom = QgsGeometry::fromPolylineXY( mPoints.at( 0 ).at( 0 ) );
784  else
786  }
787  }
788  break;
789  }
790  }
791  return geom;
792 }
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:124
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.
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:126
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:127
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 QgsMultiPolygon.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
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:86
const QgsMapToPixel * getCoordinateTransform()
Gets the current coordinate transform.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
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 current map units per pixel.
QgsPointXY toMapCoordinates(int x, int y) const
Transform device coordinates to map (world) coordinates.
QgsPointXY transform(const QgsPointXY &p) const
Transform the point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:82
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:467
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(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
@ Antialiasing
Use antialiasing while drawing.
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
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:91
@ 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:81
@ ICON_CROSS
A cross is used to highlight points (+)
Definition: qgsrubberband.h:86
@ 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:96
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 addGeometry(const QgsGeometry &geometry, QgsVectorLayer *layer, bool doUpdate=true)
Adds the geometry of an existing feature to a rubberband This is useful for multi feature highlightin...
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
int numberOfVertices() const
Returns count of vertices in all lists of mPoint.
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:938
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:832
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:75
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
Definition: qgsgeometry.h:85
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
Definition: qgsgeometry.h:81
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
Definition: qgsgeometry.h:51
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
Definition: qgsgeometry.h:92
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
const QgsCoordinateReferenceSystem & crs