QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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( QgsSymbol::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 
57 QPolygonF lineStringToQPolygonF( const QgsLineString *line )
58 {
59  const double *srcX = line->xData();
60  const double *srcY = line->yData();
61  const int count = line->numPoints();
62  QPolygonF thisRes( count );
63  QPointF *dest = thisRes.data();
64  for ( int i = 0; i < count; ++i )
65  {
66  *dest++ = QPointF( *srcX++, *srcY++ );
67  }
68  return thisRes;
69 }
70 
71 QPolygonF curveToPolygonF( const QgsCurve *curve )
72 {
73  if ( const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( curve ) )
74  {
75  return lineStringToQPolygonF( line );
76  }
77  else
78  {
79  std::unique_ptr< QgsLineString > straightened( curve->curveToLine() );
80  return lineStringToQPolygonF( straightened.get() );
81  }
82 }
83 
84 QList<QList<QPolygonF> > QgsLegendPatchShape::toQPolygonF( QgsSymbol::SymbolType type, QSizeF size ) const
85 {
86  if ( isNull() || type != mSymbolType )
87  return QgsStyle::defaultStyle()->defaultPatchAsQPolygonF( type, size );
88 
89  // scale and translate to desired size
90 
91  const QRectF bounds = mGeometry.boundingBox().toRectF();
92 
93  double dx = 0;
94  double dy = 0;
95  if ( mPreserveAspectRatio && bounds.height() > 0 && bounds.width() > 0 )
96  {
97  const double scaling = std::min( size.width() / bounds.width(), size.height() / bounds.height() );
98  const QSizeF scaledSize = bounds.size() * scaling;
99  dx = ( size.width() - scaledSize.width() ) / 2.0;
100  dy = ( size.height() - scaledSize.height() ) / 2.0;
101  size = scaledSize;
102  }
103 
104  // important -- the transform needs to flip from north-up to painter style "increasing y down" coordinates
105  QPolygonF targetRectPoly = QPolygonF() << QPointF( dx, dy + size.height() )
106  << QPointF( dx + size.width(), dy + size.height() )
107  << QPointF( dx + size.width(), dy )
108  << QPointF( dx, dy );
109  QTransform t;
110 
111  if ( bounds.width() > 0 && bounds.height() > 0 )
112  {
113  QPolygonF patchRectPoly = QPolygonF( bounds );
114  //workaround QT Bug #21329
115  patchRectPoly.pop_back();
116 
117  QTransform::quadToQuad( patchRectPoly, targetRectPoly, t );
118  }
119  else if ( bounds.width() > 0 )
120  {
121  t = QTransform::fromScale( size.width() / bounds.width(), 1 ).translate( -bounds.left(), size.height() / 2 - bounds.y() );
122  }
123  else if ( bounds.height() > 0 )
124  {
125  t = QTransform::fromScale( 1, size.height() / bounds.height() ).translate( size.width() / 2 - bounds.x(), -bounds.top() );
126  }
127 
128  QgsGeometry geom = mGeometry;
129  geom.transform( t );
130 
131  switch ( mSymbolType )
132  {
133  case QgsSymbol::Marker:
134  {
135  QPolygonF points;
136 
137  if ( QgsWkbTypes::flatType( mGeometry.wkbType() ) == QgsWkbTypes::MultiPoint )
138  {
139  const QgsGeometry patch = geom;
140  for ( auto it = patch.vertices_begin(); it != patch.vertices_end(); ++it )
141  points << QPointF( ( *it ).x(), ( *it ).y() );
142  }
143  else
144  {
145  points << QPointF( static_cast< int >( size.width() ) / 2, static_cast< int >( size.height() ) / 2 );
146  }
147  return QList< QList<QPolygonF> >() << ( QList< QPolygonF >() << points );
148  }
149 
150  case QgsSymbol::Line:
151  {
152  QList< QList<QPolygonF> > res;
153  const QgsGeometry patch = geom;
154  for ( auto it = patch.const_parts_begin(); it != patch.const_parts_end(); ++it )
155  {
156  res << ( QList< QPolygonF >() << curveToPolygonF( qgsgeometry_cast< const QgsCurve * >( *it ) ) );
157  }
158  return res;
159  }
160 
161  case QgsSymbol::Fill:
162  {
163  QList< QList<QPolygonF> > res;
164 
165  const QgsGeometry patch = geom;
166  for ( auto it = patch.const_parts_begin(); it != patch.const_parts_end(); ++it )
167  {
168  QList<QPolygonF> thisPart;
169  const QgsCurvePolygon *surface = qgsgeometry_cast< const QgsCurvePolygon * >( *it );
170  if ( !surface )
171  continue;
172 
173  if ( !surface->exteriorRing() )
174  continue;
175 
176  thisPart << curveToPolygonF( surface->exteriorRing() );
177 
178  for ( int i = 0; i < surface->numInteriorRings(); ++i )
179  thisPart << curveToPolygonF( surface->interiorRing( i ) );
180  res << thisPart;
181  }
182 
183  return res;
184  }
185 
186  case QgsSymbol::Hybrid:
187  return QList< QList<QPolygonF> >();
188  }
189 
190  return QList< QList<QPolygonF> >();
191 }
192 
193 void QgsLegendPatchShape::readXml( const QDomElement &element, const QgsReadWriteContext & )
194 {
195  mGeometry = QgsGeometry::fromWkt( element.attribute( QStringLiteral( "wkt" ) ) );
196  mPreserveAspectRatio = element.attribute( QStringLiteral( "preserveAspect" ) ).toInt();
197  mSymbolType = static_cast< QgsSymbol::SymbolType >( element.attribute( QStringLiteral( "type" ) ).toInt() );
198 }
199 
200 void QgsLegendPatchShape::writeXml( QDomElement &element, QDomDocument &, const QgsReadWriteContext & ) const
201 {
202  element.setAttribute( QStringLiteral( "wkt" ), mGeometry.isNull() ? QString() : mGeometry.asWkt( ) );
203  element.setAttribute( QStringLiteral( "preserveAspect" ), mPreserveAspectRatio ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
204  element.setAttribute( QStringLiteral( "type" ), QString::number( mSymbolType ) );
205 }
206 
208 {
209  return mSymbolType;
210 }
211 
213 {
214  mSymbolType = type;
215 }
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
qgspolygon.h
QgsLegendPatchShape::toQPolygonF
QList< QList< QPolygonF > > toQPolygonF(QgsSymbol::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:84
QgsGeometry::transform
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Definition: qgsgeometry.cpp:2813
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:57
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
qgslinestring.h
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:35
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:1880
QgsCurvePolygon::exteriorRing
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
Definition: qgscurvepolygon.h:87
QgsLegendPatchShape::QgsLegendPatchShape
QgsLegendPatchShape()=default
Constructor for a null QgsLegendPatchShape.
QgsGeometry::isNull
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
QgsWkbTypes::flatType
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:702
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:35
QgsRectangle::toRectF
QRectF toRectF() const
Returns a QRectF with same coordinates as the rectangle.
Definition: qgsrectangle.h:468
QgsLineString::yData
const double * yData() const
Returns a const pointer to the y vertex data.
Definition: qgslinestring.h:232
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:1873
curveToPolygonF
QPolygonF curveToPolygonF(const QgsCurve *curve)
Definition: qgslegendpatchshape.cpp:71
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsLegendPatchShape::symbolType
QgsSymbol::SymbolType symbolType() const
Returns the symbol type associated with this patch.
Definition: qgslegendpatchshape.cpp:207
QgsLineString::xData
const double * xData() const
Returns a const pointer to the x vertex data.
Definition: qgslinestring.h:221
QgsStyle::defaultStyle
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:127
QgsCurvePolygon::numInteriorRings
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
Definition: qgscurvepolygon.h:77
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
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:367
qgslegendpatchshape.h
QgsSymbol::Fill
@ Fill
Fill symbol.
Definition: qgssymbol.h:89
QgsCurvePolygon::interiorRing
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
Definition: qgscurvepolygon.h:100
QgsGeometry::fromWkt
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
Definition: qgsgeometry.cpp:154
qgsstyle.h
QgsGeometry::asWkt
QString asWkt(int precision=17) const
Exports the geometry to WKT.
Definition: qgsgeometry.cpp:1288
QgsStyle::defaultPatchAsQPolygonF
QList< QList< QPolygonF > > defaultPatchAsQPolygonF(QgsSymbol::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:1201
QgsLegendPatchShape::setSymbolType
void setSymbolType(QgsSymbol::SymbolType type)
Sets the symbol type associated with this patch.
Definition: qgslegendpatchshape.cpp:212
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsWkbTypes::MultiPoint
@ MultiPoint
Definition: qgswkbtypes.h:76
QgsSymbol::Line
@ Line
Line symbol.
Definition: qgssymbol.h:88
QgsSymbol::Marker
@ Marker
Marker symbol.
Definition: qgssymbol.h:87
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:996
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:1843
QgsSymbol::SymbolType
SymbolType
Type of the symbol.
Definition: qgssymbol.h:86
QgsSymbol::Hybrid
@ Hybrid
Hybrid symbol.
Definition: qgssymbol.h:90
QgsGeometry::vertices_begin
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
Definition: qgsgeometry.cpp:1836
QgsLineString::numPoints
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
Definition: qgslinestring.cpp:703
QgsLegendPatchShape::writeXml
void writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
Definition: qgslegendpatchshape.cpp:200
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.
QgsLegendPatchShape::readXml
void readXml(const QDomElement &element, const QgsReadWriteContext &context)
Read settings from a DOM element.
Definition: qgslegendpatchshape.cpp:193
QgsGeometry::wkbType
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Definition: qgsgeometry.cpp:345
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