QGIS API Documentation  3.23.0-Master (22c16f2067)
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 }
SymbolType
Symbol types.
Definition: qgis.h:183
@ 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:125
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:127
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:44
const double * yData() const
Returns a const pointer to the y vertex data.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
const double * xData() const
Returns a const pointer to the x vertex data.
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:131
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:1215
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:938
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:702
QPolygonF lineStringToQPolygonF(const QgsLineString *line)
QPolygonF curveToPolygonF(const QgsCurve *curve)