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