QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 
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( Qgis::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  {
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 
151  {
152  QList< QList<QPolygonF> > res;
153  const QgsGeometry patch = geom;
155  {
156  for ( auto it = patch.const_parts_begin(); it != patch.const_parts_end(); ++it )
157  {
158  res << ( QList< QPolygonF >() << curveToPolygonF( qgsgeometry_cast< const QgsCurve * >( *it ) ) );
159  }
160  }
161  return res;
162  }
163 
165  {
166  QList< QList<QPolygonF> > res;
167 
168  const QgsGeometry patch = geom;
169  for ( auto it = patch.const_parts_begin(); it != patch.const_parts_end(); ++it )
170  {
171  QList<QPolygonF> thisPart;
172  const QgsCurvePolygon *surface = qgsgeometry_cast< const QgsCurvePolygon * >( *it );
173  if ( !surface )
174  continue;
175 
176  if ( !surface->exteriorRing() )
177  continue;
178 
179  thisPart << curveToPolygonF( surface->exteriorRing() );
180 
181  for ( int i = 0; i < surface->numInteriorRings(); ++i )
182  thisPart << curveToPolygonF( surface->interiorRing( i ) );
183  res << thisPart;
184  }
185 
186  return res;
187  }
188 
190  return QList< QList<QPolygonF> >();
191  }
192 
193  return QList< QList<QPolygonF> >();
194 }
195 
196 void QgsLegendPatchShape::readXml( const QDomElement &element, const QgsReadWriteContext & )
197 {
198  mGeometry = QgsGeometry::fromWkt( element.attribute( QStringLiteral( "wkt" ) ) );
199  mPreserveAspectRatio = element.attribute( QStringLiteral( "preserveAspect" ) ).toInt();
200  mSymbolType = static_cast< Qgis::SymbolType >( element.attribute( QStringLiteral( "type" ) ).toInt() );
201 }
202 
203 void QgsLegendPatchShape::writeXml( QDomElement &element, QDomDocument &, const QgsReadWriteContext & ) const
204 {
205  element.setAttribute( QStringLiteral( "wkt" ), mGeometry.isNull() ? QString() : mGeometry.asWkt( ) );
206  element.setAttribute( QStringLiteral( "preserveAspect" ), mPreserveAspectRatio ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
207  element.setAttribute( QStringLiteral( "type" ), QString::number( static_cast< int >( mSymbolType ) ) );
208 }
209 
211 {
212  return mSymbolType;
213 }
214 
216 {
217  mSymbolType = type;
218 }
SymbolType
Symbol types.
Definition: qgis.h:168
@ 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:124
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.
Q_GADGET bool isNull
Definition: qgsgeometry.h:126
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.
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.
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.
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...
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.
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)