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