QGIS API Documentation 4.3.0-Master (ffcfc20b9b4)
Loading...
Searching...
No Matches
qgslabelingresults.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslabelingresults.cpp
3 -------------------
4 begin : February 2021
5 copyright : (C) Nyall Dawson
6 email : nyall dot dawson 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
16#include "qgslabelingresults.h"
17
18#include "feature.h"
19#include "labelposition.h"
20#include "qgslabelsearchtree.h"
21#include "qgslinestring.h"
22#include "qgsmapsettings.h"
23#include "qgspolygon.h"
24
26 : mLabelSearchTree( enableSearchTree ? std::make_unique< QgsLabelSearchTree >() : nullptr )
27{}
28
30
32{
33 return static_cast< bool >( mLabelSearchTree );
34}
35
37 pal::LabelPosition *labelPos,
38 QgsFeatureId featureId,
39 const QString &layerName,
40 const QString &labeltext,
41 const QFont &labelfont,
42 bool diagram,
43 bool pinned,
44 const QString &providerId,
45 bool isUnplaced,
46 long long linkedId
47)
48{
49 if ( !labelPos )
50 {
51 return false;
52 }
53
54 QVector<QgsPointXY> cornerPoints;
55 QVector< double > cornerPointsX;
56 QVector< double > cornerPointsY;
57 cornerPoints.resize( 4 );
58 cornerPointsX.resize( 5 );
59 cornerPointsY.resize( 5 );
60 double xMin = std::numeric_limits< double >::max();
61 double yMin = std::numeric_limits< double >::max();
62 double xMax = std::numeric_limits< double >::lowest();
63 double yMax = std::numeric_limits< double >::lowest();
64 for ( int i = 0; i < 4; ++i )
65 {
66 // we have to transform the bounding box to convert pre-rotated label positions back to real world locations
67 const QPointF res = mTransform.map( QPointF( labelPos->getX( i ), labelPos->getY( i ) ) );
68 cornerPoints[i] = QgsPointXY( res );
69 cornerPointsX[i] = res.x();
70 cornerPointsY[i] = res.y();
71 xMin = std::min( xMin, res.x() );
72 xMax = std::max( xMax, res.x() );
73 yMin = std::min( yMin, res.y() );
74 yMax = std::max( yMax, res.y() );
75 }
76 cornerPointsX[4] = cornerPointsX[0];
77 cornerPointsY[4] = cornerPointsY[0];
78
79 pal::LabelPosition *next = labelPos->nextPart();
80 long long uniqueLinkedId = 0;
81 if ( linkedId != 0 )
82 uniqueLinkedId = linkedId;
83 else if ( next )
84 uniqueLinkedId = mNextFeatureId++;
85
86 const QgsRectangle bounds( xMin, yMin, xMax, yMax );
87 const QgsGeometry labelGeometry( std::make_unique< QgsPolygon >( new QgsLineString( cornerPointsX, cornerPointsY ) ) );
88 auto newEntry = std::make_unique< QgsLabelPosition >(
89 featureId,
90 -labelPos->getAlpha() * 180 / M_PI + mMapSettings.rotation(),
91 cornerPoints,
92 bounds,
93 labelPos->getWidth(),
94 labelPos->getHeight(),
95 layerName,
96 labeltext,
97 labelfont,
98 labelPos->getUpsideDown(),
99 diagram,
100 pinned,
101 providerId,
102 labelGeometry,
103 isUnplaced
104 );
105 newEntry->groupedLabelId = uniqueLinkedId;
106
107 if ( uniqueLinkedId != 0 )
108 {
109 mLinkedLabelHash[uniqueLinkedId].append( newEntry.get() );
110 }
111
112 if ( mLabelSearchTree )
113 {
114 mLabelSearchTree->mSpatialIndex.insert( newEntry.get(), bounds );
115 }
116 mOwnedPositions.emplace_back( std::move( newEntry ) );
117
118 if ( next )
119 {
120 return insertLabel( next, featureId, layerName, labeltext, labelfont, diagram, pinned, providerId, isUnplaced, uniqueLinkedId );
121 }
122 return true;
123}
124
126{
127 const QPointF origin = position.origin();
128 const QPointF destination = position.destination();
129
130 auto newEntry = std::make_unique< QgsCalloutPosition >( position );
131
132 if ( mLabelSearchTree )
133 {
134 mLabelSearchTree->mCalloutIndex.insert( newEntry.get(), QgsRectangle( origin.x(), origin.y(), origin.x(), origin.y() ) );
135 mLabelSearchTree->mCalloutIndex.insert( newEntry.get(), QgsRectangle( destination.x(), destination.y(), destination.x(), destination.y() ) );
136 }
137
138 mOwnedCalloutPositions.emplace_back( std::move( newEntry ) );
139
140 return true;
141}
142
143QList<QgsLabelPosition> QgsLabelingResults::allLabels() const
144{
145 QList<QgsLabelPosition> res;
146 res.reserve( static_cast< qsizetype>( mOwnedPositions.size() ) );
147 for ( const std::unique_ptr< QgsLabelPosition > &pos : mOwnedPositions )
148 {
149 res.append( *pos );
150 }
151 return res;
152}
153
154QList<QgsLabelPosition> QgsLabelingResults::labelsAtPosition( const QgsPointXY &p ) const
155{
156 QList<QgsLabelPosition> positions;
157
158 QList<QgsLabelPosition *> positionPointers;
159 if ( mLabelSearchTree )
160 {
161 mLabelSearchTree->label( p, positionPointers );
162 QList<QgsLabelPosition *>::const_iterator pointerIt = positionPointers.constBegin();
163 for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
164 {
165 positions.push_back( QgsLabelPosition( **pointerIt ) );
166 }
167 }
168
169 return positions;
170}
171
172QList<QgsLabelPosition> QgsLabelingResults::labelsWithinRect( const QgsRectangle &r ) const
173{
174 QList<QgsLabelPosition> positions;
175
176 QList<QgsLabelPosition *> positionPointers;
177 if ( mLabelSearchTree )
178 {
179 mLabelSearchTree->labelsInRect( r, positionPointers );
180 QList<QgsLabelPosition *>::const_iterator pointerIt = positionPointers.constBegin();
181 for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
182 {
183 positions.push_back( QgsLabelPosition( **pointerIt ) );
184 }
185 }
186
187 return positions;
188}
189
190QList<QgsLabelPosition> QgsLabelingResults::groupedLabelPositions( long long groupId ) const
191{
192 QList<QgsLabelPosition> positions;
193 if ( mLabelSearchTree )
194 {
195 const QList<QgsLabelPosition *> positionPointers = mLinkedLabelHash.value( groupId );
196 positions.reserve( positionPointers.size() );
197 for ( const QgsLabelPosition *pos : positionPointers )
198 positions.push_back( QgsLabelPosition( *pos ) );
199 }
200 return positions;
201}
202
203QList<QgsCalloutPosition> QgsLabelingResults::calloutsWithinRectangle( const QgsRectangle &rectangle ) const
204{
205 QList<QgsCalloutPosition> positions;
206
207 if ( mLabelSearchTree )
208 {
209 const QList<const QgsCalloutPosition *> positionPointers = mLabelSearchTree->calloutsInRectangle( rectangle );
210 for ( const QgsCalloutPosition *pos : positionPointers )
211 {
212 positions.push_back( QgsCalloutPosition( *pos ) );
213 }
214 }
215
216 return positions;
217}
218
220{
221 mMapSettings = settings;
222 if ( !qgsDoubleNear( settings.rotation(), 0.0 ) )
223 {
224 // build a transform to convert points from real world to pre-rotated label positions
225 const QgsPointXY center = settings.visibleExtent().center();
226 mTransform = QTransform::fromTranslate( center.x(), center.y() );
227 mTransform.rotate( mMapSettings.rotation() );
228 mTransform.translate( -center.x(), -center.y() );
229 }
230 else
231 {
232 mTransform = QTransform();
233 }
234}
Represents the calculated placement of a map label callout line.
QPointF origin() const
Returns the origin of the callout line, in map coordinates.
QPointF destination() const
Returns the destination of the callout line, in map coordinates.
A geometry is the spatial representation of a feature.
Represents the calculated placement of a map label.
Queries the labeling structure at a given point.
bool insertCallout(const QgsCalloutPosition &position)
Inserts a rendered callout position.
bool hasSearchTree() const
Returns true if the results were constructed with search tree enabled.
QList< QgsCalloutPosition > calloutsWithinRectangle(const QgsRectangle &rectangle) const
Returns a list of callouts with origins or destinations inside the given rectangle.
QgsLabelingResults(bool enableSearchTree=true)
Constructor for QgsLabelingResults.
bool insertLabel(pal::LabelPosition *labelPos, QgsFeatureId featureId, const QString &layerName, const QString &labeltext, const QFont &labelfont, bool diagram=false, bool pinned=false, const QString &providerId=QString(), bool isUnplaced=false, long long linkedId=0)
Inserts label position.
void setMapSettings(const QgsMapSettings &settings)
Sets the map settings associated with the labeling run.
QList< QgsLabelPosition > allLabels() const
Returns a list of all labels generated by the labeling run.
QList< QgsLabelPosition > labelsAtPosition(const QgsPointXY &p) const
Returns the details of any labels placed at the specified point (in map coordinates).
QList< QgsLabelPosition > groupedLabelPositions(long long groupId) const
Returns a list of all label positions sharing the same group ID (i.e.
QList< QgsLabelPosition > labelsWithinRect(const QgsRectangle &r) const
Returns the details of any labels placed within the specified rectangle (in map coordinates).
Line string geometry type, with support for z-dimension and m-values.
Contains configuration for rendering maps.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
Represents a 2D point.
Definition qgspointxy.h:62
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
A rectangle specified with double values.
QgsPointXY center
LabelPosition is a candidate feature label position.
double getAlpha() const
Returns the angle to rotate text (in radians).
double getHeight() const
double getWidth() const
double getX(int i=0) const
Returns the down-left x coordinate.
double getY(int i=0) const
Returns the down-left y coordinate.
bool getUpsideDown() const
LabelPosition * nextPart() const
Returns the next part of this label position (i.e.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7557
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features