QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgslegendpatchshape.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslegendpatchshape.cpp
3  -------------------
4 begin : April 2020
5 copyright : (C) 2020 by Nyall Dawson
6 email : 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 
24 QgsLegendPatchShape::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 
52 void QgsLegendPatchShape::setPreserveAspectRatio( bool preserveAspectRatio )
53 {
54  mPreserveAspectRatio = preserveAspectRatio;
55 }
56 
58 {
59  return mScaleToTargetSize;
60 }
61 
63 {
64  mScaleToTargetSize = scale;
65 }
66 
67 QPolygonF 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 
81 QPolygonF 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 
143 QList<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 
156  if ( QgsWkbTypes::flatType( mGeometry.wkbType() ) == QgsWkbTypes::MultiPoint )
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 
215 void 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 
222 void 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 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
qgspolygon.h
QgsLegendPatchShape::geometry
QgsGeometry geometry() const
Returns the geometry for the patch shape.
Definition: qgslegendpatchshape.cpp:37
lineStringToQPolygonF
QPolygonF lineStringToQPolygonF(const QgsLineString *line)
Definition: qgslegendpatchshape.cpp:67
QgsLegendPatchShape::setPreserveAspectRatio
void setPreserveAspectRatio(bool preserve)
Sets whether the patch shape should preserve its aspect ratio when it is resized to fit a desired leg...
Definition: qgslegendpatchshape.cpp:52
Qgis::SymbolType::Fill
@ Fill
Fill symbol.
Qgis::SymbolType::Line
@ Line
Line symbol.
qgslinestring.h
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsGeometry::const_parts_end
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
Definition: qgsgeometry.cpp:2026
QgsGeometry::transform
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.
Definition: qgsgeometry.cpp:3128
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:96
QgsLegendPatchShape::QgsLegendPatchShape
QgsLegendPatchShape()=default
Constructor for a null QgsLegendPatchShape.
QgsWkbTypes::flatType
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:732
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:34
QgsGeometry::fromWkt
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
QgsRectangle::toRectF
QRectF toRectF() const
Returns a QRectF with same coordinates as the rectangle.
Definition: qgsrectangle.h:500
QgsLineString::yData
const double * yData() const
Returns a const pointer to the y vertex data.
Definition: qgslinestring.h:424
QgsGeometry::const_parts_begin
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
Definition: qgsgeometry.cpp:2019
curveToPolygonF
QPolygonF curveToPolygonF(const QgsCurve *curve)
Definition: qgslegendpatchshape.cpp:81
QgsLegendPatchShape::setScaleToOutputSize
void setScaleToOutputSize(bool scale)
Sets whether the patch shape should by resized to the desired target size when rendering.
Definition: qgslegendpatchshape.cpp:62
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsStyle::defaultPatchAsQPolygonF
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
QgsLineString::xData
const double * xData() const
Returns a const pointer to the x vertex data.
Definition: qgslinestring.h:413
QgsStyle::defaultStyle
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
QgsCurvePolygon::numInteriorRings
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Definition: qgscurvepolygon.h:86
QgsLegendPatchShape::preserveAspectRatio
bool preserveAspectRatio() const
Returns true if the patch shape should preserve its aspect ratio when it is resized to fit a desired ...
Definition: qgslegendpatchshape.cpp:47
QgsLegendPatchShape::setGeometry
void setGeometry(const QgsGeometry &geometry)
Sets the geometry for the patch shape.
Definition: qgslegendpatchshape.cpp:42
Qgis::SymbolType
SymbolType
Symbol types.
Definition: qgis.h:205
QgsLegendPatchShape::scaleToOutputSize
bool scaleToOutputSize() const
Returns true if the patch shape should by resized to the desired target size when rendering.
Definition: qgslegendpatchshape.cpp:57
QgsLegendPatchShape::scaledGeometry
QgsGeometry scaledGeometry(QSizeF size) const
Returns the patch shape's geometry, scaled to the given size.
Definition: qgslegendpatchshape.cpp:94
QgsGeometry::isEmpty
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Definition: qgsgeometry.cpp:379
QgsGeometry::isNull
bool isNull
Definition: qgsgeometry.h:127
qgslegendpatchshape.h
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:122
QgsLegendPatchShape::setSymbolType
void setSymbolType(Qgis::SymbolType type)
Sets the symbol type associated with this patch.
Definition: qgslegendpatchshape.cpp:234
qgsstyle.h
Qgis::SymbolType::Hybrid
@ Hybrid
Hybrid symbol.
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
QgsGeometry::asWkt
QString asWkt(int precision=17) const
Exports the geometry to WKT.
Definition: qgsgeometry.cpp:1407
QgsLegendPatchShape::toQPolygonF
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...
Definition: qgslegendpatchshape.cpp:143
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsWkbTypes::MultiPoint
@ MultiPoint
Definition: qgswkbtypes.h:76
QgsLegendPatchShape::symbolType
Qgis::SymbolType symbolType() const
Returns the symbol type associated with this patch.
Definition: qgslegendpatchshape.cpp:229
QgsWkbTypes::geometryType
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
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:1080
QgsGeometry::vertices_end
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
Definition: qgsgeometry.cpp:1989
QgsGeometry::vertices_begin
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
Definition: qgsgeometry.cpp:1982
QgsLineString::numPoints
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
Definition: qgslinestring.cpp:986
QgsLegendPatchShape::writeXml
void writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
Definition: qgslegendpatchshape.cpp:222
QgsCurve::curveToLine
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.
Qgis::SymbolType::Marker
@ Marker
Marker symbol.
QgsLegendPatchShape::readXml
void readXml(const QDomElement &element, const QgsReadWriteContext &context)
Read settings from a DOM element.
Definition: qgslegendpatchshape.cpp:215
QgsGeometry::wkbType
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Definition: qgsgeometry.cpp:357
qgsmultilinestring.h
QgsLegendPatchShape::isNull
bool isNull() const
Returns true if the patch shape is a null QgsLegendPatchShape, which indicates that the default legen...
Definition: qgslegendpatchshape.cpp:32