34#include "moc_qgsrubberband.cpp"
36using namespace Qt::StringLiterals;
41 , mGeometryType( geometryType )
43 reset( geometryType );
44 QColor color( Qt::lightGray );
68 if ( mBrush.color() == color )
71 mBrush.setColor( color );
76 mPen.setColor( color );
81 mSecondaryPen.setColor( color );
86 mPen.setWidthF(
width );
97 mSvgRenderer = std::make_unique<QSvgRenderer>( path );
98 mSvgOffset = drawOffset;
108 mPen.setStyle( penStyle );
113 mBrush.setStyle( brushStyle );
119 mGeometryType = geometryType;
128 mPreviewItems.push_back( std::unique_ptr< QgsRubberBandPreviewItem>( item ) );
135 mPreviewItems.clear();
141 if ( geometryIndex < 0 )
143 geometryIndex = mPoints.size() - 1;
146 if ( geometryIndex < 0 || geometryIndex > mPoints.size() )
151 if ( geometryIndex == mPoints.size() )
162 if ( mPoints.at( geometryIndex ).isEmpty() )
165 ringIndex = mPoints.at( geometryIndex ).size() - 1;
168 if ( ringIndex > mPoints.at( geometryIndex ).size() )
171 if ( ringIndex == mPoints.at( geometryIndex ).size() )
175 mPoints[geometryIndex][ringIndex].append( p );
178 if ( mPoints.at( geometryIndex ).at( ringIndex ).size() == 2 && mPoints.at( geometryIndex ).at( ringIndex ).at( 0 ) == mPoints.at( geometryIndex ).at( ringIndex ).at( 1 ) )
180 mPoints[geometryIndex][ringIndex].last() = p;
184 mPoints[geometryIndex][ringIndex].append( p );
198 if ( geometryIndex < 0 || ringIndex < 0 || mPoints.size() <= geometryIndex || mPoints.at( geometryIndex ).size() <= ringIndex || mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
203 if ( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() != mPoints.at( geometryIndex ).at( ringIndex ).constLast() )
205 mPoints[geometryIndex][ringIndex].append( mPoints.at( geometryIndex ).at( ringIndex ).constFirst() );
219 if ( geometryIndex < 0
221 || mPoints.size() <= geometryIndex
222 || mPoints.at( geometryIndex ).size() <= ringIndex
223 || mPoints.at( geometryIndex ).at( ringIndex ).size() <= index
224 || mPoints.at( geometryIndex ).at( ringIndex ).size() < -index
225 || mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
233 index = mPoints.at( geometryIndex ).at( ringIndex ).size() + index;
235 mPoints[geometryIndex][ringIndex].removeAt( index );
246 removePoint( -1, doUpdate, geometryIndex, ringIndex );
251 if ( geometryIndex < 0 || ringIndex < 0 || mPoints.size() <= geometryIndex || mPoints.at( geometryIndex ).size() <= ringIndex || mPoints.at( geometryIndex ).at( ringIndex ).isEmpty() )
256 mPoints[geometryIndex][ringIndex].last() = p;
264 if ( geometryIndex < 0 || ringIndex < 0 || index < 0 || mPoints.size() <= geometryIndex || mPoints.at( geometryIndex ).size() <= ringIndex || mPoints.at( geometryIndex ).at( ringIndex ).size() <= index )
269 mPoints[geometryIndex][ringIndex][index] = p;
279 reset( mGeometryType );
291 reset( mGeometryType );
328 int idx = mPoints.size();
340 QgsDebugError( u
"Could not transform rubber band geometry to map CRS"_s );
373 if ( line.isEmpty() )
392 addPoint( pt,
false, idx, ringIdx );
402 if ( poly.isEmpty() )
410 addPoint( pt,
false, idx, ringIdx );
452 reset( other->mGeometryType );
453 mPoints = other->mPoints;
460 if ( mPoints.isEmpty() )
467 if ( QPaintDevice *device = p->device() )
479 QVector<QVector<QPolygonF>> shapes;
480 shapes.reserve( mPoints.size() );
481 for (
const QgsPolygonXY &poly : std::as_const( mPoints ) )
483 QVector<QPolygonF> rings;
484 rings.reserve( poly.size() );
487 QVector<QPointF> pts;
488 pts.reserve( line.size() );
492 if ( pts.isEmpty() || std::abs( pts.last().x() - cur.x() ) > 1 || std::abs( pts.last().y() - cur.y() ) > 1 )
497 shapes.append( rings );
504 lineSymbol->startRender( context );
505 for (
const QVector<QPolygonF> &shape : std::as_const( shapes ) )
507 for (
const QPolygonF &ring : shape )
509 lineSymbol->renderPolyline( ring,
nullptr, context );
512 lineSymbol->stopRender( context );
516 fillSymbol->startRender( context );
517 for (
const QVector<QPolygonF> &shape : std::as_const( shapes ) )
519 for (
const QPolygonF &ring : shape )
521 fillSymbol->renderPolygon( ring,
nullptr,
nullptr, context );
524 fillSymbol->stopRender( context );
528 int iterations = mSecondaryPen.color().isValid() ? 2 : 1;
529 for (
int i = 0; i < iterations; ++i )
531 if ( i == 0 && iterations > 1 )
535 p->setBrush( Qt::NoBrush );
536 p->setPen( mSecondaryPen );
541 p->setBrush( mBrush );
545 for (
const QVector<QPolygonF> &shape : std::as_const( shapes ) )
555 for (
const auto &item : mPreviewItems )
559 item->render( context );
567 if ( rings.size() == 1 )
574 for (
const QPolygonF &poly : rings )
576 path.addPolygon( poly );
584 switch ( mGeometryType )
588 p->drawPolygon( pts );
594 const auto constPts = pts;
595 for ( QPointF pt : constPts )
600 qreal s = ( mIconSize - 1 ) / 2.0;
608 p->drawLine( QLineF( x - s, y, x + s, y ) );
609 p->drawLine( QLineF( x, y - s, x, y + s ) );
613 p->drawLine( QLineF( x - s, y - s, x + s, y + s ) );
614 p->drawLine( QLineF( x - s, y + s, x + s, y - s ) );
618 p->drawLine( QLineF( x - s, y - s, x + s, y - s ) );
619 p->drawLine( QLineF( x + s, y - s, x + s, y + s ) );
620 p->drawLine( QLineF( x + s, y + s, x - s, y + s ) );
621 p->drawLine( QLineF( x - s, y + s, x - s, y - s ) );
625 p->drawRect( QRectF(
static_cast<int>( x - s ),
static_cast<int>( y - s ), mIconSize, mIconSize ) );
629 p->drawEllipse( QRectF(
static_cast<int>( x - s ),
static_cast<int>( y - s ), mIconSize, mIconSize ) );
635 QPointF pts[] = { QPointF( x, y - s ), QPointF( x + s, y ), QPointF( x, y + s ), QPointF( x - s, y ) };
637 p->drawPolygon( pts, 4 );
639 p->drawPolyline( pts, 4 );
645 QRectF viewBox = mSvgRenderer->viewBoxF();
646 QRectF r( mSvgOffset.x(), mSvgOffset.y(), viewBox.width(), viewBox.height() );
649 mSvgRenderer->render( p, r );
660 p->drawPolyline( pts );
668 if ( mPoints.isEmpty() )
678 double iconSize = ( mIconSize + 1 ) / 2.;
681 QRectF viewBox = mSvgRenderer->viewBoxF();
682 iconSize = std::max( std::fabs( mSvgOffset.x() ) + .5 * viewBox.width(), std::fabs( mSvgOffset.y() ) + .5 * viewBox.height() );
686 qreal w = ( ( mIconSize - 1 ) / 2 + mPen.widthF() );
689 for (
const QgsPolygonXY &poly : std::as_const( mPoints ) )
691 for (
const QgsPointXY &point : poly.at( 0 ) )
693 QgsPointXY p( point.x() + mTranslationOffsetX, point.y() + mTranslationOffsetY );
712 return mComponentsToRender;
717 mComponentsToRender = components;
726 for (
const std::unique_ptr<QgsRubberBandPreviewItem> &previewItem : mPreviewItems )
728 const QRectF itemBounds = previewItem->boundingRect();
729 if ( itemBounds.isValid() )
731 res = res.united( itemBounds );
740 return mSymbol.get();
760 mTranslationOffsetX = dx;
761 mTranslationOffsetY = dy;
767 return mPoints.size();
772 if ( geometryIndex < 0 || geometryIndex >= mPoints.size() || mPoints.at( geometryIndex ).isEmpty() )
774 return mPoints.at( geometryIndex ).at( 0 ).size();
780 for (
const QgsPolygonXY &poly : std::as_const( mPoints ) )
784 count += ring.size();
792 if ( i < 0 || ringIndex < 0 || j < 0 || mPoints.size() <= i || mPoints.at( i ).size() <= ringIndex || mPoints.at( i ).at( ringIndex ).size() <= j )
795 return &mPoints[i][ringIndex][j];
802 switch ( mGeometryType )
814 for (
const QgsPolygonXY &poly : std::as_const( mPoints ) )
816 if ( poly.isEmpty() )
818 multiPoint.append( poly.at( 0 ) );
827 if ( !mPoints.isEmpty() )
829 if ( mPoints.size() > 1 )
832 for (
const QgsPolygonXY &poly : std::as_const( mPoints ) )
834 if ( poly.isEmpty() )
836 multiPolyline.append( poly.at( 0 ) );
842 if ( !mPoints.at( 0 ).isEmpty() )
864 return mRubberBand.data();
QFlags< RubberBandComponent > RubberBandComponents
Rubber band components.
RubberBandIconType
Rubber band icon type.
@ Circle
A circle is used to highlight points (○).
@ Box
A box is used to highlight points (□).
@ CrossPlus
A cross is used to highlight points (+).
@ Diamond
A diamond is used to highlight points (◇).
@ BoxFilled
A filled box is used to highlight points (■).
@ SVG
An SVG image is used to highlight points.
@ CrossX
A cross is used to highlight points (x).
@ DiamondFilled
A filled diamond is used to highlight points (◆).
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
@ Antialiasing
Use antialiasing while drawing.
@ Symbol
Base symbol component.
@ PreviewItems
Preview overlayer items.
WkbType
The WKB type describes the number of dimensions a geometry has.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
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.
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.
QRectF boundingRect() const override
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.
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.
static QgsProject * instance()
Returns the QgsProject singleton instance.
A rectangle specified with double values.
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 setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected).
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
Abstract interface for rendering custom preview overlays attached to a QgsRubberBand.
QgsRubberBandPreviewItem(QgsRubberBand *rubberBand)
Constructor for a QgsRubberBandPreviewItem, attached to the specified rubberBand.
QgsRubberBand * rubberBand()
Returns the rubber band associated with the item.
virtual QRectF boundingRect() const
Returns the bounding rect required for drawing the preview item.
Responsible for drawing transient features (e.g.
QRectF boundingRect() const override
void clearPreviewItems()
Clears all registered preview items.
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.
void setIcon(Qgis::RubberBandIconType icon)
Sets the icon type to highlight point geometries.
~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.
Qgis::RubberBandComponents renderedComponents() const
Returns the rubber band components that will be rendered for this band.
QgsGeometry asGeometry() const
Returns the rubberband as a Geometry.
void setRenderedComponents(Qgis::RubberBandComponents components)
Sets the rubber band components that should be rendered for this band.
int size() const
Returns number of geometries.
void paint(QPainter *p) override
Paints the rubber band in response to an update event.
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.
Qgis::RubberBandIconType icon() const
Returns the current icon type to highlight point geometries.
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 addPreviewItem(QgsRubberBandPreviewItem *item)
Adds a custom preview item decorator to the rubber band.
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 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.
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.
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.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
#define QgsDebugError(str)