QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgslegendpatchshape.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslegendpatchshape.cpp
3 -------------------
4begin : April 2020
5copyright : (C) 2020 by Nyall Dawson
6email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgslegendpatchshape.h"
19#include "qgsmultilinestring.h"
20#include "qgslinestring.h"
21#include "qgspolygon.h"
22#include "qgsstyle.h"
23
24QgsLegendPatchShape::QgsLegendPatchShape( Qgis::SymbolType type, const QgsGeometry &geometry, bool preserveAspectRatio )
25 : mSymbolType( type )
26 , mGeometry( geometry )
27 , mPreserveAspectRatio( preserveAspectRatio )
28{
29
30}
31
33{
34 return mGeometry.isNull() || mGeometry.isEmpty();
35}
36
38{
39 return mGeometry;
40}
41
43{
44 mGeometry = geometry;
45}
46
48{
49 return mPreserveAspectRatio;
50}
51
52void QgsLegendPatchShape::setPreserveAspectRatio( bool preserveAspectRatio )
53{
54 mPreserveAspectRatio = preserveAspectRatio;
55}
56
58{
59 return mScaleToTargetSize;
60}
61
63{
64 mScaleToTargetSize = scale;
65}
66
67QPolygonF lineStringToQPolygonF( const QgsLineString *line )
68{
69 const double *srcX = line->xData();
70 const double *srcY = line->yData();
71 const int count = line->numPoints();
72 QPolygonF thisRes( count );
73 QPointF *dest = thisRes.data();
74 for ( int i = 0; i < count; ++i )
75 {
76 *dest++ = QPointF( *srcX++, *srcY++ );
77 }
78 return thisRes;
79}
80
81QPolygonF curveToPolygonF( const QgsCurve *curve )
82{
83 if ( const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( curve ) )
84 {
85 return lineStringToQPolygonF( line );
86 }
87 else
88 {
89 const std::unique_ptr< QgsLineString > straightened( curve->curveToLine() );
90 return lineStringToQPolygonF( straightened.get() );
91 }
92}
93
95{
96 QgsGeometry geom = mGeometry;
97 if ( mScaleToTargetSize )
98 {
99 // scale and translate to desired size
100
101 const QRectF bounds = mGeometry.boundingBox().toRectF();
102
103 double dx = 0;
104 double dy = 0;
105 if ( mPreserveAspectRatio && bounds.height() > 0 && bounds.width() > 0 )
106 {
107 const double scaling = std::min( size.width() / bounds.width(), size.height() / bounds.height() );
108 const QSizeF scaledSize = bounds.size() * scaling;
109 dx = ( size.width() - scaledSize.width() ) / 2.0;
110 dy = ( size.height() - scaledSize.height() ) / 2.0;
111 size = scaledSize;
112 }
113
114 // important -- the transform needs to flip from north-up to painter style "increasing y down" coordinates
115 const QPolygonF targetRectPoly = QPolygonF() << QPointF( dx, dy + size.height() )
116 << QPointF( dx + size.width(), dy + size.height() )
117 << QPointF( dx + size.width(), dy )
118 << QPointF( dx, dy );
119 QTransform t;
120
121 if ( bounds.width() > 0 && bounds.height() > 0 )
122 {
123 QPolygonF patchRectPoly = QPolygonF( bounds );
124 //workaround QT Bug #21329
125 patchRectPoly.pop_back();
126
127 QTransform::quadToQuad( patchRectPoly, targetRectPoly, t );
128 }
129 else if ( bounds.width() > 0 )
130 {
131 t = QTransform::fromScale( size.width() / bounds.width(), 1 ).translate( -bounds.left(), size.height() / 2 - bounds.y() );
132 }
133 else if ( bounds.height() > 0 )
134 {
135 t = QTransform::fromScale( 1, size.height() / bounds.height() ).translate( size.width() / 2 - bounds.x(), -bounds.top() );
136 }
137
138 geom.transform( t );
139 }
140 return geom;
141}
142
143QList<QList<QPolygonF> > QgsLegendPatchShape::toQPolygonF( Qgis::SymbolType type, QSizeF size ) const
144{
145 if ( isNull() || type != mSymbolType )
146 return QgsStyle::defaultStyle()->defaultPatchAsQPolygonF( type, size );
147
148 const QgsGeometry geom = scaledGeometry( size );
149
150 switch ( mSymbolType )
151 {
153 {
154 QPolygonF points;
155
157 {
158 const QgsGeometry patch = geom;
159 for ( auto it = patch.vertices_begin(); it != patch.vertices_end(); ++it )
160 points << QPointF( ( *it ).x(), ( *it ).y() );
161 }
162 else
163 {
164 points << QPointF( static_cast< int >( size.width() ) / 2, static_cast< int >( size.height() ) / 2 );
165 }
166 return QList< QList<QPolygonF> >() << ( QList< QPolygonF >() << points );
167 }
168
170 {
171 QList< QList<QPolygonF> > res;
172 const QgsGeometry patch = geom;
174 {
175 for ( auto it = patch.const_parts_begin(); it != patch.const_parts_end(); ++it )
176 {
177 res << ( QList< QPolygonF >() << curveToPolygonF( qgsgeometry_cast< const QgsCurve * >( *it ) ) );
178 }
179 }
180 return res;
181 }
182
184 {
185 QList< QList<QPolygonF> > res;
186
187 const QgsGeometry patch = geom;
188 for ( auto it = patch.const_parts_begin(); it != patch.const_parts_end(); ++it )
189 {
190 QList<QPolygonF> thisPart;
191 const QgsCurvePolygon *surface = qgsgeometry_cast< const QgsCurvePolygon * >( *it );
192 if ( !surface )
193 continue;
194
195 if ( !surface->exteriorRing() )
196 continue;
197
198 thisPart << curveToPolygonF( surface->exteriorRing() );
199
200 for ( int i = 0; i < surface->numInteriorRings(); ++i )
201 thisPart << curveToPolygonF( surface->interiorRing( i ) );
202 res << thisPart;
203 }
204
205 return res;
206 }
207
209 return QList< QList<QPolygonF> >();
210 }
211
212 return QList< QList<QPolygonF> >();
213}
214
215void QgsLegendPatchShape::readXml( const QDomElement &element, const QgsReadWriteContext & )
216{
217 mGeometry = QgsGeometry::fromWkt( element.attribute( QStringLiteral( "wkt" ) ) );
218 mPreserveAspectRatio = element.attribute( QStringLiteral( "preserveAspect" ) ).toInt();
219 mSymbolType = static_cast< Qgis::SymbolType >( element.attribute( QStringLiteral( "type" ) ).toInt() );
220}
221
222void QgsLegendPatchShape::writeXml( QDomElement &element, QDomDocument &, const QgsReadWriteContext & ) const
223{
224 element.setAttribute( QStringLiteral( "wkt" ), mGeometry.isNull() ? QString() : mGeometry.asWkt( ) );
225 element.setAttribute( QStringLiteral( "preserveAspect" ), mPreserveAspectRatio ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
226 element.setAttribute( QStringLiteral( "type" ), QString::number( static_cast< int >( mSymbolType ) ) );
227}
228
230{
231 return mSymbolType;
232}
233
235{
236 mSymbolType = type;
237}
SymbolType
Symbol types.
Definition: qgis.h:206
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
@ Hybrid
Hybrid symbol.
Curve polygon geometry type.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
virtual QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const =0
Returns a new line string geometry corresponding to a segmentized approximation of the curve.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
QString asWkt(int precision=17) const
Exports the geometry to WKT.
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
bool scaleToOutputSize() const
Returns true if the patch shape should by resized to the desired target size when rendering.
void setSymbolType(Qgis::SymbolType type)
Sets the symbol type associated with this patch.
void readXml(const QDomElement &element, const QgsReadWriteContext &context)
Read settings from a DOM element.
QList< QList< QPolygonF > > toQPolygonF(Qgis::SymbolType type, QSizeF size) const
Converts the patch shape to a set of QPolygonF objects representing how the patch should be drawn for...
QgsGeometry scaledGeometry(QSizeF size) const
Returns the patch shape's geometry, scaled to the given size.
void setGeometry(const QgsGeometry &geometry)
Sets the geometry for the patch shape.
bool preserveAspectRatio() const
Returns true if the patch shape should preserve its aspect ratio when it is resized to fit a desired ...
bool isNull() const
Returns true if the patch shape is a null QgsLegendPatchShape, which indicates that the default legen...
QgsLegendPatchShape()=default
Constructor for a null QgsLegendPatchShape.
void setPreserveAspectRatio(bool preserve)
Sets whether the patch shape should preserve its aspect ratio when it is resized to fit a desired leg...
void writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
QgsGeometry geometry() const
Returns the geometry for the patch shape.
void setScaleToOutputSize(bool scale)
Sets whether the patch shape should by resized to the desired target size when rendering.
Qgis::SymbolType symbolType() const
Returns the symbol type associated with this patch.
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:45
const double * yData() const
Returns a const pointer to the y vertex data.
const double * xData() const
Returns a const pointer to the x vertex data.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
The class is used as a container of context for various read/write operations on other objects.
QRectF toRectF() const
Returns a QRectF with same coordinates as the rectangle.
Definition: qgsrectangle.h:500
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
QList< QList< QPolygonF > > defaultPatchAsQPolygonF(Qgis::SymbolType type, QSizeF size) const
Returns the default patch geometry for the given symbol type and size as a set of QPolygonF objects (...
Definition: qgsstyle.cpp:1199
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:968
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:732
QPolygonF lineStringToQPolygonF(const QgsLineString *line)
QPolygonF curveToPolygonF(const QgsCurve *curve)