QGIS API Documentation 3.41.0-Master (af5edcb665c)
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 && 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
176void QgsRubberBand::closePoints( bool doUpdate, int geometryIndex, int ringIndex )
177{
178 if ( geometryIndex < 0 || ringIndex < 0 || mPoints.size() <= geometryIndex || mPoints.at( geometryIndex ).size() <= ringIndex || mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
179 {
180 return;
181 }
182
183 if ( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() != mPoints.at( geometryIndex ).at( ringIndex ).constLast() )
184 {
185 mPoints[geometryIndex][ringIndex].append( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() );
186 }
187
188 if ( doUpdate )
189 {
190 setVisible( true );
191 updateRect();
192 update();
193 }
194}
195
196
197void QgsRubberBand::removePoint( int index, bool doUpdate /* = true*/, int geometryIndex /* = 0*/, int ringIndex /* = 0*/ )
198{
199 if ( geometryIndex < 0 || ringIndex < 0 || mPoints.size() <= geometryIndex || mPoints.at( geometryIndex ).size() <= ringIndex || mPoints.at( geometryIndex ).at( ringIndex ).size() <= index || mPoints.at( geometryIndex ).at( ringIndex ).size() < -index || mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
200 {
201 return;
202 }
203
204 // negative index removes from end, e.g., -1 removes last one
205 if ( index < 0 )
206 {
207 index = mPoints.at( geometryIndex ).at( ringIndex ).size() + index;
208 }
209 mPoints[geometryIndex][ringIndex].removeAt( index );
210
211 if ( doUpdate )
212 {
213 updateRect();
214 update();
215 }
216}
217
218void QgsRubberBand::removeLastPoint( int geometryIndex, bool doUpdate /* = true*/, int ringIndex /* = 0*/ )
219{
220 removePoint( -1, doUpdate, geometryIndex, ringIndex );
221}
222
223void QgsRubberBand::movePoint( const QgsPointXY &p, int geometryIndex, int ringIndex )
224{
225 if ( geometryIndex < 0 || ringIndex < 0 || mPoints.size() <= geometryIndex || mPoints.at( geometryIndex ).size() <= ringIndex || mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
226 {
227 return;
228 }
229
230 mPoints[geometryIndex][ringIndex].last() = p;
231
232 updateRect();
233 update();
234}
235
236void QgsRubberBand::movePoint( int index, const QgsPointXY &p, int geometryIndex, int ringIndex )
237{
238 if ( geometryIndex < 0 || ringIndex < 0 || index < 0 || mPoints.size() <= geometryIndex || mPoints.at( geometryIndex ).size() <= ringIndex || mPoints.at( geometryIndex ).at( ringIndex ).size() <= index )
239 {
240 return;
241 }
242
243 mPoints[geometryIndex][ringIndex][index] = p;
244
245 updateRect();
246 update();
247}
248
250{
251 if ( geom.isNull() )
252 {
253 reset( mGeometryType );
254 return;
255 }
256
257 reset( geom.type() );
258 addGeometry( geom, layer );
259}
260
262{
263 if ( geom.isNull() )
264 {
265 reset( mGeometryType );
266 return;
267 }
268
269 reset( geom.type() );
270 addGeometry( geom, crs );
271}
272
273void QgsRubberBand::addGeometry( const QgsGeometry &geometry, QgsMapLayer *layer, bool doUpdate )
274{
275 QgsGeometry geom = geometry;
276 if ( layer )
277 {
279 try
280 {
281 geom.transform( ct );
282 }
283 catch ( QgsCsException & )
284 {
285 return;
286 }
287 }
288
289 addGeometry( geom, QgsCoordinateReferenceSystem(), doUpdate );
290}
291
292void QgsRubberBand::addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs, bool doUpdate )
293{
294 if ( geometry.isEmpty() )
295 {
296 return;
297 }
298
299 //maprender object of canvas
301
302 int idx = mPoints.size();
303
304 QgsGeometry geom = geometry;
305 if ( crs.isValid() )
306 {
308 try
309 {
310 geom.transform( ct );
311 }
312 catch ( QgsCsException & )
313 {
314 QgsDebugError( QStringLiteral( "Could not transform rubber band geometry to map CRS" ) );
315 return;
316 }
317 }
318
319 Qgis::WkbType geomType = geom.wkbType();
321 {
322 QgsPointXY pt = geom.asPoint();
323 addPoint( pt, false, idx );
324 }
326 {
327 const QgsMultiPointXY mpt = geom.asMultiPoint();
328 for ( const QgsPointXY &pt : mpt )
329 {
330 addPoint( pt, false, idx );
331 idx++;
332 }
333 }
334 else if ( QgsWkbTypes::geometryType( geomType ) == Qgis::GeometryType::Line && !QgsWkbTypes::isMultiType( geomType ) )
335 {
336 const QgsPolylineXY line = geom.asPolyline();
337 for ( const QgsPointXY &pt : line )
338 {
339 addPoint( pt, false, idx );
340 }
341 }
342 else if ( QgsWkbTypes::geometryType( geomType ) == Qgis::GeometryType::Line && QgsWkbTypes::isMultiType( geomType ) )
343 {
344 const QgsMultiPolylineXY mline = geom.asMultiPolyline();
345 for ( const QgsPolylineXY &line : mline )
346 {
347 if ( line.isEmpty() )
348 {
349 continue;
350 }
351 for ( const QgsPointXY &pt : line )
352 {
353 addPoint( pt, false, idx );
354 }
355 idx++;
356 }
357 }
359 {
360 const QgsPolygonXY poly = geom.asPolygon();
361 int ringIdx = 0;
362 for ( const QgsPolylineXY &ring : poly )
363 {
364 for ( const QgsPointXY &pt : ring )
365 {
366 addPoint( pt, false, idx, ringIdx );
367 }
368 ringIdx++;
369 }
370 }
372 {
373 const QgsMultiPolygonXY multipoly = geom.asMultiPolygon();
374 for ( const QgsPolygonXY &poly : multipoly )
375 {
376 if ( poly.isEmpty() )
377 continue;
378
379 int ringIdx = 0;
380 for ( const QgsPolylineXY &ring : poly )
381 {
382 for ( const QgsPointXY &pt : ring )
383 {
384 addPoint( pt, false, idx, ringIdx );
385 }
386 ringIdx++;
387 }
388 idx++;
389 }
390 }
391 else
392 {
393 return;
394 }
395
396 setVisible( true );
397 if ( doUpdate )
398 {
399 updateRect();
400 update();
401 }
402}
403
405{
406 if ( !mMapCanvas )
407 {
408 return;
409 }
410
411 const QgsMapToPixel *transform = mMapCanvas->getCoordinateTransform();
412 QgsPointXY ll = transform->toMapCoordinates( rect.left(), rect.bottom() );
413 QgsPointXY lr = transform->toMapCoordinates( rect.right(), rect.bottom() );
414 QgsPointXY ul = transform->toMapCoordinates( rect.left(), rect.top() );
415 QgsPointXY ur = transform->toMapCoordinates( rect.right(), rect.top() );
416
418 addPoint( ll, false );
419 addPoint( lr, false );
420 addPoint( ur, false );
421 addPoint( ul, true );
422}
423
425{
426 reset( other->mGeometryType );
427 mPoints = other->mPoints;
428 updateRect();
429 update();
430}
431
432void QgsRubberBand::paint( QPainter *p )
433{
434 if ( mPoints.isEmpty() )
435 return;
436
437 QVector<QVector<QPolygonF>> shapes;
438 shapes.reserve( mPoints.size() );
439 for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
440 {
441 QVector<QPolygonF> rings;
442 rings.reserve( poly.size() );
443 for ( const QgsPolylineXY &line : poly )
444 {
445 QVector<QPointF> pts;
446 pts.reserve( line.size() );
447 for ( const QgsPointXY &pt : line )
448 {
449 const QPointF cur = toCanvasCoordinates( QgsPointXY( pt.x() + mTranslationOffsetX, pt.y() + mTranslationOffsetY ) ) - pos();
450 if ( pts.isEmpty() || std::abs( pts.last().x() - cur.x() ) > 1 || std::abs( pts.last().y() - cur.y() ) > 1 )
451 pts.append( cur );
452 }
453 rings.append( pts );
454 }
455 shapes.append( rings );
456 }
457
458 if ( QgsLineSymbol *lineSymbol = dynamic_cast<QgsLineSymbol *>( mSymbol.get() ) )
459 {
462
463 lineSymbol->startRender( context );
464 for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
465 {
466 for ( const QPolygonF &ring : shape )
467 {
468 lineSymbol->renderPolyline( ring, nullptr, context );
469 }
470 }
471 lineSymbol->stopRender( context );
472 }
473 else if ( QgsFillSymbol *fillSymbol = dynamic_cast<QgsFillSymbol *>( mSymbol.get() ) )
474 {
477
478 fillSymbol->startRender( context );
479 for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
480 {
481 for ( const QPolygonF &ring : shape )
482 {
483 fillSymbol->renderPolygon( ring, nullptr, nullptr, context );
484 }
485 }
486 fillSymbol->stopRender( context );
487 }
488 else
489 {
490 int iterations = mSecondaryPen.color().isValid() ? 2 : 1;
491 for ( int i = 0; i < iterations; ++i )
492 {
493 if ( i == 0 && iterations > 1 )
494 {
495 // first iteration with multi-pen painting, so use secondary pen
496 mSecondaryPen.setWidthF( mPen.widthF() + QgsGuiUtils::scaleIconSize( 2 ) );
497 p->setBrush( Qt::NoBrush );
498 p->setPen( mSecondaryPen );
499 }
500 else
501 {
502 // "top" layer, use primary pen/brush
503 p->setBrush( mBrush );
504 p->setPen( mPen );
505 }
506
507 for ( const QVector<QPolygonF> &shape : std::as_const( shapes ) )
508 {
509 drawShape( p, shape );
510 }
511 }
512 }
513}
514
515void QgsRubberBand::drawShape( QPainter *p, const QVector<QPolygonF> &rings )
516{
517 if ( rings.size() == 1 )
518 {
519 drawShape( p, rings.at( 0 ) );
520 }
521 else
522 {
523 QPainterPath path;
524 for ( const QPolygonF &poly : rings )
525 {
526 path.addPolygon( poly );
527 }
528 p->drawPath( path );
529 }
530}
531
532void QgsRubberBand::drawShape( QPainter *p, const QVector<QPointF> &pts )
533{
534 switch ( mGeometryType )
535 {
537 {
538 p->drawPolygon( pts );
539 }
540 break;
541
543 {
544 const auto constPts = pts;
545 for ( QPointF pt : constPts )
546 {
547 double x = pt.x();
548 double y = pt.y();
549
550 qreal s = ( mIconSize - 1 ) / 2.0;
551
552 switch ( mIconType )
553 {
554 case ICON_NONE:
555 break;
556
557 case ICON_CROSS:
558 p->drawLine( QLineF( x - s, y, x + s, y ) );
559 p->drawLine( QLineF( x, y - s, x, y + s ) );
560 break;
561
562 case ICON_X:
563 p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
564 p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
565 break;
566
567 case ICON_BOX:
568 p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
569 p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
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_FULL_BOX:
575 p->drawRect( QRectF( static_cast<int>( x - s ), static_cast<int>( y - s ), mIconSize, mIconSize ) );
576 break;
577
578 case ICON_CIRCLE:
579 p->drawEllipse( QRectF( static_cast<int>( x - s ), static_cast<int>( y - s ), mIconSize, mIconSize ) );
580 break;
581
582 case ICON_DIAMOND:
584 {
585 QPointF pts[] = {
586 QPointF( x, y - s ),
587 QPointF( x + s, y ),
588 QPointF( x, y + s ),
589 QPointF( x - s, y )
590 };
591 if ( mIconType == ICON_FULL_DIAMOND )
592 p->drawPolygon( pts, 4 );
593 else
594 p->drawPolyline( pts, 4 );
595 break;
596 }
597
598 case ICON_SVG:
599 {
600 QRectF viewBox = mSvgRenderer->viewBoxF();
601 QRectF r( mSvgOffset.x(), mSvgOffset.y(), viewBox.width(), viewBox.height() );
602 QgsScopedQPainterState painterState( p );
603 p->translate( pt );
604 mSvgRenderer->render( p, r );
605 break;
606 }
607 }
608 }
609 }
610 break;
611
613 default:
614 {
615 p->drawPolyline( pts );
616 }
617 break;
618 }
619}
620
622{
623 if ( mPoints.isEmpty() )
624 {
626 setVisible( false );
627 return;
628 }
629
631
632#if 0 // unused?
633 double iconSize = ( mIconSize + 1 ) / 2.;
634 if ( mSvgRenderer )
635 {
636 QRectF viewBox = mSvgRenderer->viewBoxF();
637 iconSize = std::max( std::fabs( mSvgOffset.x() ) + .5 * viewBox.width(), std::fabs( mSvgOffset.y() ) + .5 * viewBox.height() );
638 }
639#endif
640
641 qreal w = ( ( mIconSize - 1 ) / 2 + mPen.widthF() ); // in canvas units
642
643 QgsRectangle r; // in canvas units
644 for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
645 {
646 for ( const QgsPointXY &point : poly.at( 0 ) )
647 {
648 QgsPointXY p( point.x() + mTranslationOffsetX, point.y() + mTranslationOffsetY );
649 p = m2p.transform( p );
650 // no need to normalize the rectangle -- we know it is already normal
651 QgsRectangle rect( p.x() - w, p.y() - w, p.x() + w, p.y() + w, false );
653 }
654 }
655
656 // This is an hack to pass QgsMapCanvasItem::setRect what it
657 // expects (encoding of position and size of the item)
658 qreal res = m2p.mapUnitsPerPixel();
659 QgsPointXY topLeft = m2p.toMapCoordinates( r.xMinimum(), r.yMinimum() );
660 QgsRectangle rect( topLeft.x(), topLeft.y(), topLeft.x() + r.width() * res, topLeft.y() - r.height() * res );
661
662 setRect( rect );
663}
664
666{
667 return mSymbol.get();
668}
669
671{
672 mSymbol.reset( symbol );
673}
674
676{
677 // re-compute rectangle
678 // See https://github.com/qgis/QGIS/issues/20566
679 // NOTE: could be optimized by saving map-extent
680 // of rubberband and simply re-projecting
681 // that to device-rectangle on "updatePosition"
682 updateRect();
683}
684
685void QgsRubberBand::setTranslationOffset( double dx, double dy )
686{
687 mTranslationOffsetX = dx;
688 mTranslationOffsetY = dy;
689 updateRect();
690}
691
693{
694 return mPoints.size();
695}
696
697int QgsRubberBand::partSize( int geometryIndex ) const
698{
699 if ( geometryIndex < 0 || geometryIndex >= mPoints.size() || mPoints.at( geometryIndex ).isEmpty() )
700 return 0;
701 return mPoints.at( geometryIndex ).at( 0 ).size();
702}
703
705{
706 int count = 0;
707 for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
708 {
709 for ( const QgsPolylineXY &ring : poly )
710 {
711 count += ring.size();
712 }
713 }
714 return count;
715}
716
717const QgsPointXY *QgsRubberBand::getPoint( int i, int j, int ringIndex ) const
718{
719 if ( i < 0 || ringIndex < 0 || j < 0 || mPoints.size() <= i || mPoints.at( i ).size() <= ringIndex || mPoints.at( i ).at( ringIndex ).size() <= j )
720 return nullptr;
721 else
722 return &mPoints[i][ringIndex][j];
723}
724
726{
727 QgsGeometry geom;
728
729 switch ( mGeometryType )
730 {
732 {
733 geom = QgsGeometry::fromMultiPolygonXY( mPoints );
734 break;
735 }
736
738 {
739 QgsMultiPointXY multiPoint;
740
741 for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
742 {
743 if ( poly.isEmpty() )
744 continue;
745 multiPoint.append( poly.at( 0 ) );
746 }
747 geom = QgsGeometry::fromMultiPointXY( multiPoint );
748 break;
749 }
750
752 default:
753 {
754 if ( !mPoints.isEmpty() )
755 {
756 if ( mPoints.size() > 1 )
757 {
758 QgsMultiPolylineXY multiPolyline;
759 for ( const QgsPolygonXY &poly : std::as_const( mPoints ) )
760 {
761 if ( poly.isEmpty() )
762 continue;
763 multiPolyline.append( poly.at( 0 ) );
764 }
765 geom = QgsGeometry::fromMultiPolylineXY( multiPolyline );
766 }
767 else
768 {
769 if ( !mPoints.at( 0 ).isEmpty() )
770 geom = QgsGeometry::fromPolylineXY( mPoints.at( 0 ).at( 0 ) );
771 else
773 }
774 }
775 break;
776 }
777 }
778 return geom;
779}
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