QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 "qgslabelsearchtree.h"
19 #include "qgsvectorlayer.h"
21 #include "diagram/qgsdiagram.h"
22 
23 #include "feature.h"
24 #include "labelposition.h"
25 
26 
28  const QgsDiagramLayerSettings* diagSettings,
29  const QgsDiagramRendererV2* diagRenderer,
30  const QString& layerId,
31  const QgsFields& fields,
34  bool ownsSource )
35  : QgsAbstractLabelProvider( layerId )
36  , mSettings( *diagSettings )
37  , mDiagRenderer( diagRenderer->clone() )
38  , mFields( fields )
39  , mLayerCrs( crs )
40  , mSource( source )
41  , mOwnsSource( ownsSource )
42 {
43  init();
44 }
45 
46 
48  : QgsAbstractLabelProvider( layer->id() )
49  , mSettings( *layer->diagramLayerSettings() )
50  , mDiagRenderer( layer->diagramRenderer()->clone() )
51  , mFields( layer->fields() )
52  , mLayerCrs( layer->crs() )
53  , mSource( ownFeatureLoop ? new QgsVectorLayerFeatureSource( layer ) : nullptr )
54  , mOwnsSource( ownFeatureLoop )
55 {
56  init();
57 }
58 
59 
61 {
62  mName = mLayerId;
63  mPriority = 1 - mSettings.getPriority() / 10.0; // convert 0..10 --> 1..0
66 }
67 
68 
70 {
71  if ( mOwnsSource )
72  delete mSource;
73 
74  qDeleteAll( mFeatures );
75 
76  // renderer is owned by mSettings
77 }
78 
79 
81 {
82  if ( !mSource )
83  {
84  // we have created the provider with "own feature loop" == false
85  // so it is assumed that prepare() has been already called followed by registerFeature() calls
86  return mFeatures;
87  }
88 
89  QStringList attributeNames;
90  if ( !prepare( context, attributeNames ) )
91  return QList<QgsLabelFeature*>();
92 
93  QgsRectangle layerExtent = context.extent();
96 
97  QgsFeatureRequest request;
98  request.setFilterRect( layerExtent );
99  request.setSubsetOfAttributes( attributeNames, mFields );
100  QgsFeatureIterator fit = mSource->getFeatures( request );
101 
102 
103  QgsFeature fet;
104  while ( fit.nextFeature( fet ) )
105  {
106  registerFeature( fet, context );
107  }
108 
109  return mFeatures;
110 }
111 
112 
114 {
115 #if 1 // XXX strk
116  // features are pre-rotated but not scaled/translated,
117  // so we only disable rotation here. Ideally, they'd be
118  // also pre-scaled/translated, as suggested here:
119  // http://hub.qgis.org/issues/11856
120  QgsMapToPixel xform = context.mapToPixel();
121  xform.setMapRotation( 0, 0, 0 );
122 #else
123  const QgsMapToPixel& xform = context.mapToPixel();
124 #endif
125 
126  QgsDiagramLabelFeature* dlf = dynamic_cast<QgsDiagramLabelFeature*>( label->getFeaturePart()->feature() );
127 
128  QgsFeature feature;
129  feature.setFields( mFields );
130  feature.setValid( true );
131  feature.setFeatureId( label->getFeaturePart()->featureId() );
132  feature.setAttributes( dlf->attributes() );
133 
134  //calculate top-left point for diagram
135  //first, calculate the centroid of the label (accounts for PAL creating
136  //rotated labels when we do not want to draw the diagrams rotated)
137  double centerX = 0;
138  double centerY = 0;
139  for ( int i = 0; i < 4; ++i )
140  {
141  centerX += label->getX( i );
142  centerY += label->getY( i );
143  }
144  QgsPoint outPt( centerX / 4.0, centerY / 4.0 );
145  //then, calculate the top left point for the diagram with this center position
146  QgsPoint centerPt = xform.transform( outPt.x() - label->getWidth() / 2,
147  outPt.y() - label->getHeight() / 2 );
148 
149  mSettings.getRenderer()->renderDiagram( feature, context, centerPt.toQPointF() );
150 
151  //insert into label search tree to manipulate position interactively
152  mEngine->results()->mLabelSearchTree->insertLabel( label, label->getFeaturePart()->featureId(), mLayerId, QString(), QFont(), true, false );
153 
154 }
155 
156 
158 {
160  const QgsMapSettings& mapSettings = mEngine->mapSettings();
161 
162  if ( mapSettings.hasCrsTransformEnabled() )
163  {
164  if ( context.coordinateTransform() )
165  // this is context for layer rendering - use its CT as it includes correct datum transform
167  else
168  // otherwise fall back to creating our own CT - this one may not have the correct datum transform!
170  }
171  else
172  {
173  s2.setCoordinateTransform( nullptr );
174  }
175 
177 
178  //add attributes needed by the diagram renderer
179  Q_FOREACH ( const QString& field, s2.referencedFields( context.expressionContext(), mFields ) )
180  {
181  if ( !attributeNames.contains( field ) )
182  attributeNames << field;
183  }
184 
185  return true;
186 }
187 
188 
190 {
191  QgsLabelFeature* label = registerDiagram( feature, context, obstacleGeometry );
192  if ( label )
193  mFeatures << label;
194 }
195 
196 
198 {
199  const QgsMapSettings& mapSettings = mEngine->mapSettings();
200 
202  if ( dr )
203  {
204  QList<QgsDiagramSettings> settingList = dr->diagramSettings();
205  if ( !settingList.isEmpty() && settingList.at( 0 ).scaleBasedVisibility )
206  {
207  double minScale = settingList.at( 0 ).minScaleDenominator;
208  if ( minScale > 0 && context.rendererScale() < minScale )
209  {
210  return nullptr;
211  }
212 
213  double maxScale = settingList.at( 0 ).maxScaleDenominator;
214  if ( maxScale > 0 && context.rendererScale() > maxScale )
215  {
216  return nullptr;
217  }
218  }
219  }
220 
221  //convert geom to geos
222  const QgsGeometry* geom = feat.constGeometry();
223  QScopedPointer<QgsGeometry> extentGeom( QgsGeometry::fromRect( mapSettings.visibleExtent() ) );
224  if ( !qgsDoubleNear( mapSettings.rotation(), 0.0 ) )
225  {
226  //PAL features are prerotated, so extent also needs to be unrotated
227  extentGeom->rotate( -mapSettings.rotation(), mapSettings.visibleExtent().center() );
228  }
229 
230  const GEOSGeometry* geos_geom = nullptr;
231  QScopedPointer<QgsGeometry> preparedGeom;
232  if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, mSettings.coordinateTransform(), extentGeom.data() ) )
233  {
234  preparedGeom.reset( QgsPalLabeling::prepareGeometry( geom, context, mSettings.coordinateTransform(), extentGeom.data() ) );
235  if ( !preparedGeom.data() )
236  return nullptr;
237  geos_geom = preparedGeom.data()->asGeos();
238  }
239  else
240  {
241  geos_geom = geom->asGeos();
242  }
243 
244  if ( !geos_geom )
245  return nullptr; // invalid geometry
246 
247  GEOSGeometry* geomCopy = GEOSGeom_clone_r( QgsGeometry::getGEOSHandler(), geos_geom );
248 
249  const GEOSGeometry* geosObstacleGeom = nullptr;
250  QScopedPointer<QgsGeometry> scopedObstacleGeom;
251  if ( mSettings.isObstacle() && obstacleGeometry && QgsPalLabeling::geometryRequiresPreparation( obstacleGeometry, context, mSettings.coordinateTransform(), extentGeom.data() ) )
252  {
253  scopedObstacleGeom.reset( QgsPalLabeling::prepareGeometry( obstacleGeometry, context, mSettings.coordinateTransform(), extentGeom.data() ) );
254  geosObstacleGeom = scopedObstacleGeom.data()->asGeos();
255  }
256  else if ( mSettings.isObstacle() && obstacleGeometry )
257  {
258  geosObstacleGeom = obstacleGeometry->asGeos();
259  }
260  GEOSGeometry* geosObstacleGeomClone = nullptr;
261  if ( geosObstacleGeom )
262  {
263  geosObstacleGeomClone = GEOSGeom_clone_r( QgsGeometry::getGEOSHandler(), geosObstacleGeom );
264  }
265 
266 
267  double diagramWidth = 0;
268  double diagramHeight = 0;
269  if ( dr )
270  {
271  QSizeF diagSize = dr->sizeMapUnits( feat, context );
272  if ( diagSize.isValid() )
273  {
274  diagramWidth = diagSize.width();
275  diagramHeight = diagSize.height();
276  }
277  }
278 
279  // feature to the layer
280  bool alwaysShow = mSettings.showAllDiagrams();
281  int ddColX = mSettings.xPosColumn;
282  int ddColY = mSettings.yPosColumn;
283  double ddPosX = 0.0;
284  double ddPosY = 0.0;
285  bool ddPos = ( ddColX >= 0 && ddColY >= 0 );
286  if ( ddPos && ! feat.attribute( ddColX ).isNull() && ! feat.attribute( ddColY ).isNull() )
287  {
288  bool posXOk, posYOk;
289  ddPosX = feat.attribute( ddColX ).toDouble( &posXOk );
290  ddPosY = feat.attribute( ddColY ).toDouble( &posYOk );
291  if ( !posXOk || !posYOk )
292  {
293  ddPos = false;
294  }
295  else
296  {
298  if ( ct )
299  {
300  double z = 0;
301  ct->transformInPlace( ddPosX, ddPosY, z );
302  }
303  //data defined diagram position is always centered
304  ddPosX -= diagramWidth / 2.0;
305  ddPosY -= diagramHeight / 2.0;
306  }
307  }
308  else
309  ddPos = false;
310 
311  int ddColShow = mSettings.showColumn;
312  if ( ddColShow >= 0 && ! feat.attribute( ddColShow ).isNull() )
313  {
314  bool showOk;
315  bool ddShow = feat.attribute( ddColShow ).toDouble( &showOk );
316 
317  if ( showOk && ! ddShow )
318  return nullptr;
319  }
320 
321  QgsDiagramLabelFeature* lf = new QgsDiagramLabelFeature( feat.id(), geomCopy, QSizeF( diagramWidth, diagramHeight ) );
322  lf->setHasFixedPosition( ddPos );
323  lf->setFixedPosition( QgsPoint( ddPosX, ddPosY ) );
324  lf->setHasFixedAngle( true );
325  lf->setFixedAngle( 0 );
326  lf->setAlwaysShow( alwaysShow );
328  lf->setZIndex( mSettings.getZIndex() );
329  if ( geosObstacleGeomClone )
330  {
331  lf->setObstacleGeometry( geosObstacleGeomClone );
332  }
333 
334  if ( dr )
335  {
336  //append the diagram attributes to lbl
337  lf->setAttributes( feat.attributes() );
338  }
339 
340  QgsPoint ptZero = mapSettings.mapToPixel().toMapCoordinates( 0, 0 );
341  QgsPoint ptOne = mapSettings.mapToPixel().toMapCoordinates( 1, 0 );
342  lf->setDistLabel( ptOne.distance( ptZero ) * mSettings.distance() );
343  return lf;
344 }
QgsLabelFeature * registerDiagram(QgsFeature &feat, QgsRenderContext &context, QgsGeometry *obstacleGeometry=nullptr)
helper method to register one diagram feautre
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
static QgsGeometry * prepareGeometry(const QgsGeometry *geometry, QgsRenderContext &context, const QgsCoordinateTransform *ct, QgsGeometry *clipGeometry=nullptr)
Prepares a geometry for registration with PAL.
double rendererScale() const
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:217
virtual QSizeF sizeMapUnits(const QgsFeature &feature, const QgsRenderContext &c) const
Returns size of the diagram for a feature in map units.
QgsAttributes attributes() const
Returns the feature&#39;s attributes.
Definition: qgsfeature.cpp:110
void setMapRotation(double degrees, double cx, double cy)
Set map rotation in degrees (clockwise)
QgsPalLayerSettings::Placement mPlacement
Placement strategy.
QgsFeatureId featureId() const
Returns the unique ID of the feature.
Definition: feature.cpp:155
bool isObstacle() const
Returns whether the feature associated with a diagram acts as an obstacle for other labels or diagram...
virtual bool prepare(const QgsRenderContext &context, QStringList &attributeNames)
Prepare for registration of features.
QgsLabelFeature * feature()
Returns the parent feature.
Definition: feature.h:110
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspoint.cpp:129
double rotation() const
Return the rotation of the resulting map image Units are clockwise degrees.
double getZIndex() const
Returns the diagram z-index.
int yPosColumn
Attribute index for y coordinate (or -1 if position not data defined)
double mPriority
Default priority of labels.
void init()
initialization method - called from constructors
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspoint.cpp:363
double getY(int i=0) const
get the down-left y coordinate
const T & at(int i) const
bool isValid() const
bool contains(const QString &str, Qt::CaseSensitivity cs) const
virtual QList< QgsDiagramSettings > diagramSettings() const =0
Returns list with all diagram settings in the renderer.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
QgsVectorLayerDiagramProvider(QgsVectorLayer *layer, bool ownFeatureLoop=true)
Convenience constructor to initialize the provider from given vector layer.
Container of fields for a vector layer.
Definition: qgsfield.h:252
QgsPoint toMapCoordinates(int x, int y) const
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:115
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.
QgsCoordinateTransform * coordinateTransform()
Returns the coordinate transform associated with the layer.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
QgsDiagramRendererV2 * mDiagRenderer
Diagram renderer instance (owned by mSettings)
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:187
void setFixedPosition(const QgsPoint &point)
Set coordinates of the fixed position (relevant only if hasFixedPosition() returns true) ...
static bool geometryRequiresPreparation(const QgsGeometry *geometry, QgsRenderContext &context, const QgsCoordinateTransform *ct, QgsGeometry *clipGeometry=nullptr)
Checks whether a geometry requires preparation before registration with PAL.
const QgsMapSettings & mapSettings() const
Get associated map settings.
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:353
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
void setHasFixedPosition(bool enabled)
Set whether the label should use a fixed position instead of being automatically placed.
void reset(T *other)
The QgsMapSettings class contains configuration for rendering of the map.
QgsRectangle transformBoundingBox(const QgsRectangle &theRect, TransformDirection direction=ForwardTransform, const bool handle180Crossover=false) const
Transform a QgsRectangle to the dest Coordinate system If the direction is ForwardTransform then coor...
QgsPoint transform(const QgsPoint &p) const
Transform the point from map (world) coordinates to device coordinates.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
bool mOwnsSource
Whether layer&#39;s feature source is owned.
int xPosColumn
Attribute index for x coordinate (or -1 if position not data defined)
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.
void setFeatureId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:101
bool isNull() const
const QgsRectangle & extent() const
unsigned int mLinePlacementFlags
Extra placement flags for linestring geometries.
double getHeight() const
bool isEmpty() const
void setFixedAngle(double angle)
Set angle in degrees of the fixed angle (relevant only if hasFixedAngle() returns true) ...
const QgsCoordinateTransform * coordinateTransform() const
This class wraps a request for features to a vector layer (or directly its vector data provider)...
virtual void drawLabel(QgsRenderContext &context, pal::LabelPosition *label) const override
draw this label at the position determined by the labeling engine
unsigned int linePlacementFlags() const
Returns the diagram placement flags.
const QgsLabelingEngineV2 * mEngine
Associated labeling engine.
void setDistLabel(double dist)
Applies to "around point" placement strategy or linestring features.
Base class that can be used for any class that is capable of returning features.
QgsFields mFields
Layer&#39;s fields.
A class to represent a point.
Definition: qgspoint.h:117
const QgsMapToPixel & mapToPixel() const
Q_DECL_DEPRECATED 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:173
The QgsAbstractLabelProvider class is an interface class.
virtual void registerFeature(QgsFeature &feature, QgsRenderContext &context, QgsGeometry *obstacleGeometry=nullptr)
Register a feature for labeling as one or more QgsLabelFeature objects stored into mFeatures...
QgsCoordinateReferenceSystem mLayerCrs
Layer&#39;s CRS.
T * data() const
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
QgsLabelingResults * results() const
For internal use by the providers.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsDiagramRendererV2 * getRenderer()
Returns the diagram renderer associated with the layer.
Stores the settings for rendering of all diagrams for a layer.
Class that adds extra information to QgsLabelFeature for labeling of diagrams.
void setCoordinateTransform(QgsCoordinateTransform *transform)
Sets the coordinate transform associated with the layer.
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:204
double distance() const
Returns the distance between the diagram and the feature (in mm).
void renderDiagram(const QgsFeature &feature, QgsRenderContext &c, QPointF pos) const
Contains information about the context of a rendering operation.
void setRenderer(QgsDiagramRendererV2 *diagramRenderer)
Sets the diagram renderer associated with the layer.
The QgsLabelFeature class describes a feature that should be used within the labeling engine...
const QgsMapToPixel & mapToPixel() const
static GEOSContextHandle_t getGEOSHandler()
Return GEOS context handle.
QString mName
Name of the layer.
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...
Placement getPlacement() const
Returns the diagram placement.
virtual QList< QgsLabelFeature * > labelFeatures(QgsRenderContext &context) override
Return list of label features (they are owned by the provider and thus deleted on its destruction) ...
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), const QgsFields &fields=QgsFields()) const
Returns the set of any fields referenced by the layer&#39;s diagrams.
void setAttributes(const QgsAttributes &attrs)
Store feature&#39;s attributes - used for rendering of diagrams.
const GEOSGeometry * asGeos(double precision=0) const
Returns a geos geometry.
void setObstacleGeometry(GEOSGeometry *obstacleGeom)
Sets the label&#39;s obstacle geometry, if different to the feature geometry.
Class for storing a coordinate reference system (CRS)
QgsCoordinateTransform * clone() const
int getPriority() const
Returns the diagram priority.
int showColumn
Attribute index for visibility (or -1 if visibility not data defined)
Class for doing transforms between two map coordinate systems.
static QgsGeometry * fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
LabelPosition is a candidate feature label position.
Definition: labelposition.h:51
double toDouble(bool *ok) const
const QgsAttributes & attributes()
Get feature&#39;s attributes - used for rendering of diagrams.
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request)=0
Get an iterator for features matching the specified request.
QgsAbstractFeatureSource * mSource
Layer&#39;s feature source.
bool nextFeature(QgsFeature &f)
qreal height() const
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
QString mLayerId
Associated layer&#39;s ID, if applicable.
QgsDiagramLayerSettings mSettings
Diagram layer settings.
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
QList< QgsLabelFeature * > mFeatures
List of generated label features (owned by the provider)
qreal width() const
QgsFeatureRequest & setFilterRect(const QgsRectangle &rect)
Set rectangle from which features will be taken.
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
bool showAllDiagrams() const
Returns whether the layer should show all diagrams, including overlapping diagrams.