QGIS API Documentation  3.0.2-Girona (307d082)
qgsvectorlayerdiagramprovider.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerdiagramprovider.cpp
3  --------------------------------------
4  Date : September 2015
5  Copyright : (C) 2015 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
18 #include "qgsgeometry.h"
19 #include "qgslabelsearchtree.h"
20 #include "qgsvectorlayer.h"
22 #include "diagram/qgsdiagram.h"
23 
24 #include "feature.h"
25 #include "labelposition.h"
26 
28  : QgsAbstractLabelProvider( layer )
29  , mSettings( *layer->diagramLayerSettings() )
30  , mDiagRenderer( layer->diagramRenderer()->clone() )
31  , mFields( layer->fields() )
32  , mLayerCrs( layer->crs() )
33  , mSource( ownFeatureLoop ? new QgsVectorLayerFeatureSource( layer ) : nullptr )
34  , mOwnsSource( ownFeatureLoop )
35 {
36  init();
37 }
38 
39 
41 {
42  mName = mLayerId;
43  mPriority = 1 - mSettings.priority() / 10.0; // convert 0..10 --> 1..0
46 }
47 
48 
50 {
51  if ( mOwnsSource )
52  delete mSource;
53 
54  qDeleteAll( mFeatures );
55 
56  // renderer is owned by mSettings
57 }
58 
59 
61 {
62  if ( !mSource )
63  {
64  // we have created the provider with "own feature loop" == false
65  // so it is assumed that prepare() has been already called followed by registerFeature() calls
66  return mFeatures;
67  }
68 
69  QSet<QString> attributeNames;
70  if ( !prepare( context, attributeNames ) )
71  return QList<QgsLabelFeature *>();
72 
73  QgsRectangle layerExtent = context.extent();
76 
77  QgsFeatureRequest request;
78  request.setFilterRect( layerExtent );
79  request.setSubsetOfAttributes( attributeNames, mFields );
80  QgsFeatureIterator fit = mSource->getFeatures( request );
81 
82 
83  QgsFeature fet;
84  while ( fit.nextFeature( fet ) )
85  {
86  registerFeature( fet, context );
87  }
88 
89  return mFeatures;
90 }
91 
92 
94 {
95 #if 1 // XXX strk
96  // features are pre-rotated but not scaled/translated,
97  // so we only disable rotation here. Ideally, they'd be
98  // also pre-scaled/translated, as suggested here:
99  // https://issues.qgis.org/issues/11856
100  QgsMapToPixel xform = context.mapToPixel();
101  xform.setMapRotation( 0, 0, 0 );
102 #else
103  const QgsMapToPixel &xform = context.mapToPixel();
104 #endif
105 
106  QgsDiagramLabelFeature *dlf = dynamic_cast<QgsDiagramLabelFeature *>( label->getFeaturePart()->feature() );
107 
108  QgsFeature feature;
109  feature.setFields( mFields );
110  feature.setValid( true );
111  feature.setId( label->getFeaturePart()->featureId() );
112  feature.setAttributes( dlf->attributes() );
113 
114  context.expressionContext().setFeature( feature );
115 
116  //calculate top-left point for diagram
117  //first, calculate the centroid of the label (accounts for PAL creating
118  //rotated labels when we do not want to draw the diagrams rotated)
119  double centerX = 0;
120  double centerY = 0;
121  for ( int i = 0; i < 4; ++i )
122  {
123  centerX += label->getX( i );
124  centerY += label->getY( i );
125  }
126  QgsPointXY outPt( centerX / 4.0, centerY / 4.0 );
127  //then, calculate the top left point for the diagram with this center position
128  QgsPointXY centerPt = xform.transform( outPt.x() - label->getWidth() / 2,
129  outPt.y() - label->getHeight() / 2 );
130 
131  mSettings.renderer()->renderDiagram( feature, context, centerPt.toQPointF(), mSettings.dataDefinedProperties() );
132 
133  //insert into label search tree to manipulate position interactively
134  mEngine->results()->mLabelSearchTree->insertLabel( label, label->getFeaturePart()->featureId(), mLayerId, QString(), QFont(), true, false );
135 
136 }
137 
138 
139 bool QgsVectorLayerDiagramProvider::prepare( const QgsRenderContext &context, QSet<QString> &attributeNames )
140 {
142  const QgsMapSettings &mapSettings = mEngine->mapSettings();
143 
144  if ( context.coordinateTransform().isValid() )
145  // this is context for layer rendering - use its CT as it includes correct datum transform
147  else
148  {
149  // otherwise fall back to creating our own CT - this one may not have the correct datum transform!
153  }
154 
156 
157  bool result = s2.prepare( context.expressionContext() );
158 
159  //add attributes needed by the diagram renderer
160  attributeNames.unite( s2.referencedFields( context.expressionContext() ) );
161 
162  return result;
163 }
164 
165 
167 {
168  QgsLabelFeature *label = registerDiagram( feature, context, obstacleGeometry );
169  if ( label )
170  mFeatures << label;
171 }
172 
173 
175 {
176  const QgsMapSettings &mapSettings = mEngine->mapSettings();
177 
178  const QgsDiagramRenderer *dr = mSettings.renderer();
179  if ( dr )
180  {
181  QList<QgsDiagramSettings> settingList = dr->diagramSettings();
182  if ( !settingList.isEmpty() && settingList.at( 0 ).scaleBasedVisibility )
183  {
184  double maxScale = settingList.at( 0 ).maximumScale;
185  if ( maxScale > 0 && context.rendererScale() < maxScale )
186  {
187  return nullptr;
188  }
189 
190  double minScale = settingList.at( 0 ).minimumScale;
191  if ( minScale > 0 && context.rendererScale() > minScale )
192  {
193  return nullptr;
194  }
195  }
196  }
197 
198  // data defined show diagram? check this before doing any other processing
200  return nullptr;
201 
202  // data defined obstacle?
204 
205  //convert geom to geos
206  QgsGeometry geom = feat.geometry();
207  QgsGeometry extentGeom = QgsGeometry::fromRect( mapSettings.visibleExtent() );
208  if ( !qgsDoubleNear( mapSettings.rotation(), 0.0 ) )
209  {
210  //PAL features are prerotated, so extent also needs to be unrotated
211  extentGeom.rotate( -mapSettings.rotation(), mapSettings.visibleExtent().center() );
212  }
213 
214  GEOSGeometry *geomCopy = nullptr;
215  std::unique_ptr<QgsGeometry> scopedPreparedGeom;
216  if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, mSettings.coordinateTransform(), extentGeom ) )
217  {
218  scopedPreparedGeom.reset( new QgsGeometry( QgsPalLabeling::prepareGeometry( geom, context, mSettings.coordinateTransform(), extentGeom ) ) );
219  QgsGeometry *preparedGeom = scopedPreparedGeom.get();
220  if ( preparedGeom->isNull() )
221  return nullptr;
222  geomCopy = preparedGeom->exportToGeos();
223  }
224  else
225  {
226  geomCopy = geom.exportToGeos();
227  }
228 
229  if ( !geomCopy )
230  return nullptr; // invalid geometry
231 
232  GEOSGeometry *geosObstacleGeomClone = nullptr;
233  std::unique_ptr<QgsGeometry> scopedObstacleGeom;
234  if ( isObstacle && obstacleGeometry && QgsPalLabeling::geometryRequiresPreparation( obstacleGeometry, context, mSettings.coordinateTransform(), extentGeom ) )
235  {
236  QgsGeometry preparedObstacleGeom = QgsPalLabeling::prepareGeometry( obstacleGeometry, context, mSettings.coordinateTransform(), extentGeom );
237  geosObstacleGeomClone = preparedObstacleGeom.exportToGeos();
238  }
239  else if ( mSettings.isObstacle() && !obstacleGeometry.isNull() )
240  {
241  geosObstacleGeomClone = obstacleGeometry.exportToGeos();
242  }
243 
244  double diagramWidth = 0;
245  double diagramHeight = 0;
246  if ( dr )
247  {
248  QSizeF diagSize = dr->sizeMapUnits( feat, context );
249  if ( diagSize.isValid() )
250  {
251  diagramWidth = diagSize.width();
252  diagramHeight = diagSize.height();
253  }
254  }
255 
256  // feature to the layer
257  bool alwaysShow = mSettings.showAllDiagrams();
258  context.expressionContext().setOriginalValueVariable( alwaysShow );
260 
261  // new style data defined position
262  bool ddPos = false;
263  double ddPosX = 0.0;
264  double ddPosY = 0.0;
269  {
270  ddPosX = mSettings.dataDefinedProperties().valueAsDouble( QgsDiagramLayerSettings::PositionX, context.expressionContext(), std::numeric_limits<double>::quiet_NaN() );
271  ddPosY = mSettings.dataDefinedProperties().valueAsDouble( QgsDiagramLayerSettings::PositionY, context.expressionContext(), std::numeric_limits<double>::quiet_NaN() );
272 
273  ddPos = !std::isnan( ddPosX ) && !std::isnan( ddPosY );
274 
275  if ( ddPos )
276  {
278  if ( ct.isValid() && !ct.isShortCircuited() )
279  {
280  double z = 0;
281  ct.transformInPlace( ddPosX, ddPosY, z );
282  }
283  //data defined diagram position is always centered
284  ddPosX -= diagramWidth / 2.0;
285  ddPosY -= diagramHeight / 2.0;
286  }
287  }
288 
289  QgsDiagramLabelFeature *lf = new QgsDiagramLabelFeature( feat.id(), geomCopy, QSizeF( diagramWidth, diagramHeight ) );
290  lf->setHasFixedPosition( ddPos );
291  lf->setFixedPosition( QgsPointXY( ddPosX, ddPosY ) );
292  lf->setHasFixedAngle( true );
293  lf->setFixedAngle( 0 );
294  lf->setAlwaysShow( alwaysShow );
295  lf->setIsObstacle( isObstacle );
296  if ( geosObstacleGeomClone )
297  {
298  lf->setObstacleGeometry( geosObstacleGeomClone );
299  }
300 
301  if ( dr )
302  {
303  //append the diagram attributes to lbl
304  lf->setAttributes( feat.attributes() );
305  }
306 
307  // data defined priority?
310  {
313  priorityD = qBound( 0.0, priorityD, 10.0 );
314  priorityD = 1 - priorityD / 10.0; // convert 0..10 --> 1..0
315  lf->setPriority( priorityD );
316  }
317 
318  // z-Index
319  double zIndex = mSettings.zIndex();
322  {
323  context.expressionContext().setOriginalValueVariable( zIndex );
325  }
326  lf->setZIndex( zIndex );
327 
328  // label distance
329  QgsPointXY ptZero = mapSettings.mapToPixel().toMapCoordinates( 0, 0 );
330  QgsPointXY ptOne = mapSettings.mapToPixel().toMapCoordinates( 1, 0 );
331  double dist = mSettings.distance();
332 
335  {
338  }
339 
340  dist *= ptOne.distance( ptZero );
341 
342  lf->setDistLabel( dist );
343  return lf;
344 }
QgsFeatureId id
Definition: qgsfeature.h:71
Wrapper for iterator of features from vector data provider or vector layer.
void setCoordinateTransform(const QgsCoordinateTransform &transform)
Sets the coordinate transform associated with the layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:39
y-coordinate data defined diagram position
double rendererScale() const
Returns the renderer map scale.
void setMapRotation(double degrees, double cx, double cy)
Set map rotation in degrees (clockwise)
QgsPalLayerSettings::Placement mPlacement
Placement strategy.
QgsDiagramRenderer * mDiagRenderer
Diagram renderer instance (owned by mSettings)
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:155
QgsFeatureId featureId() const
Returns the unique ID of the feature.
Definition: feature.cpp:151
bool isObstacle() const
Returns whether the feature associated with a diagram acts as an obstacle for other labels or diagram...
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double...
QgsLabelFeature * feature()
Returns the parent feature.
Definition: feature.h:118
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
const QgsLabelingEngine * mEngine
Associated labeling engine.
QgsCoordinateTransform coordinateTransform() const
Returns the coordinate transform associated with the layer, or an invalid transform if no transformat...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
double mPriority
Default priority of labels.
void init()
initialization method - called from constructors
QgsDiagramRenderer * renderer()
Returns the diagram renderer associated with the layer.
int priority() const
Returns the diagram priority.
double getY(int i=0) const
get the down-left y coordinate
double y
Definition: qgspointxy.h:48
bool hasProperty(int key) const override
Returns true if the collection contains a property with the specified key.
A class to represent a 2D point.
Definition: qgspointxy.h:43
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the diagram&#39;s property collection, used for data defined overrides.
OperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:516
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, TransformDirection direction=ForwardTransform, const bool handle180Crossover=false) const
Transforms a rectangle from the source CRS to the destination CRS.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())=0
Get an iterator for features matching the specified request.
QgsVectorLayerDiagramProvider(QgsVectorLayer *layer, bool ownFeatureLoop=true)
Convenience constructor to initialize the provider from given vector layer.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
bool insertLabel(pal::LabelPosition *labelPos, int featureId, const QString &layerName, const QString &labeltext, const QFont &labelfont, bool diagram=false, bool pinned=false, const QString &providerId=QString())
Inserts label position.
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext()) const
Returns the set of any fields referenced by the layer&#39;s diagrams.
FeaturePart * getFeaturePart()
return the feature corresponding to this labelposition
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
void renderDiagram(const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties=QgsPropertyCollection()) const
Renders the diagram for a specified feature at a specific position in the passed render context...
Z-index for diagram ordering.
void setAlwaysShow(bool enabled)
Set whether label should be always shown (sets very high label priority)
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:251
virtual bool prepare(const QgsRenderContext &context, QSet< QString > &attributeNames)
Prepare for registration of features.
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
QList< QgsLabelFeature * > mFeatures
List of generated label features (owned by the provider)
void setHasFixedPosition(bool enabled)
Set whether the label should use a fixed position instead of being automatically placed.
The QgsMapSettings class contains configuration for rendering of the map.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Diagram priority (between 0 and 10)
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.cpp:40
QgsLabelFeature * registerDiagram(QgsFeature &feat, QgsRenderContext &context, const QgsGeometry &obstacleGeometry=QgsGeometry())
helper method to register one diagram feautre
bool mOwnsSource
Whether layer&#39;s feature source is owned.
void setIsObstacle(bool enabled)
Sets whether the feature will act as an obstacle for labels.
void setZIndex(double zIndex)
Sets the label&#39;s z-index.
const QgsRectangle & extent() const
unsigned int mLinePlacementFlags
Extra placement flags for linestring geometries.
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
bool isShortCircuited() const
Returns true if the transform short circuits because the source and destination are equivalent...
double getHeight() const
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const
Prepares the diagrams for a specified expression context.
void setFixedAngle(double angle)
Set angle in degrees of the fixed angle (relevant only if hasFixedAngle() returns true) ...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void drawLabel(QgsRenderContext &context, pal::LabelPosition *label) const override
draw this label at the position determined by the labeling engine
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context, or an invalid transform is no coordinate tr...
x-coordinate data defined diagram position
void setDistLabel(double dist)
Applies to "around point" placement strategy or linestring features.
void setId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:112
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
Whether diagram features act as obstacles for other diagrams/labels.
QgsFields mFields
Layer&#39;s fields.
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspointxy.cpp:78
const QgsMapToPixel & mapToPixel() const
The QgsAbstractLabelProvider class is an interface class.
double zIndex() const
Returns the diagram z-index.
QgsCoordinateReferenceSystem mLayerCrs
Layer&#39;s CRS.
double x
Definition: qgspointxy.h:47
void setFixedPosition(const QgsPointXY &point)
Set coordinates of the fixed position (relevant only if hasFixedPosition() returns true) ...
LinePlacementFlags linePlacementFlags() const
Returns the diagram placement flags.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
void setRenderer(QgsDiagramRenderer *diagramRenderer)
Sets the diagram renderer associated with the layer.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
QgsExpressionContext & expressionContext()
Gets the expression context.
Stores the settings for rendering of all diagrams for a layer.
Class that adds extra information to QgsLabelFeature for labeling of diagrams.
bool valueAsBool(int key, const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an boolean...
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:517
Placement
Placement modes which determine how label candidates are generated for a feature. ...
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:181
Placement placement() const
Returns the diagram placement.
double distance() const
Returns the distance between the diagram and the feature (in mm).
Contains information about the context of a rendering operation.
The QgsLabelFeature class describes a feature that should be used within the labeling engine...
const QgsMapToPixel & mapToPixel() const
Transform from destination to source CRS.
QString mName
Name of the layer.
Distance to diagram from feature.
virtual void registerFeature(QgsFeature &feature, QgsRenderContext &context, const QgsGeometry &obstacleGeometry=QgsGeometry())
Register a feature for labeling as one or more QgsLabelFeature objects stored into mFeatures...
double getWidth() const
double getX(int i=0) const
get the down-left x coordinate
void setHasFixedAngle(bool enabled)
Set whether the label should use a fixed angle instead of using angle from automatic placement...
GEOSGeometry * exportToGeos(double precision=0) const
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
QList< QgsLabelFeature * > labelFeatures(QgsRenderContext &context) override
Return list of label features (they are owned by the provider and thus deleted on its destruction) ...
virtual QList< QgsDiagramSettings > diagramSettings() const =0
Returns list with all diagram settings in the renderer.
void setAttributes(const QgsAttributes &attrs)
Store feature&#39;s attributes - used for rendering of diagrams.
void setObstacleGeometry(GEOSGeometry *obstacleGeom)
Sets the label&#39;s obstacle geometry, if different to the feature geometry.
const QgsMapSettings & mapSettings() const
Get associated map settings.
QgsLabelingResults * results() const
For internal use by the providers.
Class for doing transforms between two map coordinate systems.
LabelPosition is a candidate feature label position.
Definition: labelposition.h:55
static bool geometryRequiresPreparation(const QgsGeometry &geometry, QgsRenderContext &context, const QgsCoordinateTransform &ct, const QgsGeometry &clipGeometry=QgsGeometry())
Checks whether a geometry requires preparation before registration with PAL.
Whether to show the diagram.
virtual QSizeF sizeMapUnits(const QgsFeature &feature, const QgsRenderContext &c) const
Returns size of the diagram for a feature in map units. Returns an invalid QSizeF in case of error...
static QgsGeometry prepareGeometry(const QgsGeometry &geometry, QgsRenderContext &context, const QgsCoordinateTransform &ct, const QgsGeometry &clipGeometry=QgsGeometry())
Prepares a geometry for registration with PAL.
const QgsAttributes & attributes()
Get feature&#39;s attributes - used for rendering of diagrams.
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:170
QgsAbstractFeatureSource * mSource
Layer&#39;s feature source.
bool nextFeature(QgsFeature &f)
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const
Transforms an array of x, y and z double coordinates in place, from the source CRS to the destination...
Represents a vector layer which manages a vector based data sets.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
QString mLayerId
Associated layer&#39;s ID, if applicable.
QgsDiagramLayerSettings mSettings
Diagram layer settings.
QgsPointXY toMapCoordinates(int x, int y) const
QgsAttributes attributes
Definition: qgsfeature.h:72
bool isActive() const
Returns whether the property is currently active.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
bool showAllDiagrams() const
Returns whether the layer should show all diagrams, including overlapping diagrams.
void setPriority(double priority)
Sets the priority for labeling the feature.